gpt4 book ai didi

c# - 空合并运算符的含义?

转载 作者:太空狗 更新时间:2023-10-29 19:39:46 26 4
gpt4 key购买 nike

前阵子我编译了两个版本的代码,一个使用(Nullable<T>)x.GetValueOrDefault(y)和一个使用 (Nullable<T>)x ?? y) .

在反编译为 IL 后,我注意到 null coalesce 运算符被转换为 GetValueOrDefault打电话。

因为它是一个可以传递表达式的方法调用,在执行该方法之前对其进行评估,y似乎总是被执行。

例如:

using System;

public static class TestClass
{
private class SomeDisposable : IDisposable
{
public SomeDisposable()
{
// Allocate some native resources
}

private void finalize()
{
// Free those resources
}

~SomeDisposable()
{
finalize();
}

public void Dispose()
{
finalize();
GC.SuppressFinalize(this);
}
}

private struct TestStruct
{
public readonly SomeDisposable _someDisposable;
private readonly int _weirdNumber;

public TestStruct(int weirdNumber)
{
_weirdNumber = weirdNumber;
_someDisposable = new SomeDisposable();
}
}

public static void Main()
{
TestStruct? local = new TestStruct(0);

TestStruct local2 = local ?? new TestStruct(1);

local2._someDisposable.Dispose();
}
}

似乎会导致对象不适,并且可能还会影响性能。

首先,这是真的吗?还是 JIT 或类似的东西改变了实际执行的 ASM 代码?

其次有人可以解释为什么它有这种行为吗?

注意:这只是一个示例,并非基于真实代码,请不要发表“这是错误代码”之类的评论。

IL DASM:
好的,当我使用 .Net Framework 2.0 编译它时,它产生了与调用 null coalesce 和 GetValueOrDefault 相同的代码。使用 .Net Framework 4.0,它生成以下两个代码:

获取值或默认值:

.method private hidebysig static void  Main() cil managed
{
.entrypoint
// Code size 19 (0x13)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> nullableInt,
[1] int32 nonNullableInt)
IL_0000: nop
IL_0001: ldloca.s nullableInt
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloca.s nullableInt
IL_000b: ldc.i4.1
IL_000c: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault(!0)
IL_0011: stloc.1
IL_0012: ret
} // end of method Program::Main

空合并:

.method private hidebysig static void  Main() cil managed
{
.entrypoint
// Code size 32 (0x20)
.maxstack 2
.locals init (valuetype [mscorlib]System.Nullable`1<int32> V_0,
int32 V_1,
valuetype [mscorlib]System.Nullable`1<int32> V_2)
IL_0000: nop
IL_0001: ldloca.s V_0
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloc.0
IL_000a: stloc.2
IL_000b: ldloca.s V_2
IL_000d: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0012: brtrue.s IL_0017
IL_0014: ldc.i4.1
IL_0015: br.s IL_001e
IL_0017: ldloca.s V_2
IL_0019: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_001e: stloc.1
IL_001f: ret
} // end of method Program::Main

事实证明不再是这种情况,并且它跳过了 GetValueOrDefault共时调用HasValue返回 false。

最佳答案

After decompiling to IL I noticed that the null coalesce operator is transformed into the GetValueOrDefault call.

x ?? y 转换为 x.HasValue ? x.GetValueOrDefault() : y。它不会转换为 x.GetValueOrDefault(y),如果是的话,那将是一个编译器错误。没错,如果 x 不为 null,则不应计算 y,事实并非如此。

编辑:如果可以证明 y 的计算没有副作用(其中“副作用”包括“抛出异常”),则转换为 x.GetValueOrDefault(y) 不一定是错误的,但它仍然是我认为编译器不会执行的转换:在很多情况下这种优化都是有用的。

关于c# - 空合并运算符的含义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8780597/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com