Does C# ?? operator get called twice?
方法是否位于的左侧??C中的操作员接到两次电话?一次用于评估,一次用于分配?
在以下行中:
1 | int i = GetNullableInt() ?? default(int); |
我假设需要首先调用
??操作员(C参考)
当前C编译器中存在一个错误,它将导致计算第一个操作数的某些方面出现两次,在非常特定的情况下-但不是,
这在第7.13节的C 5规范中有记录,其中选项列表中的每个项目符号(基于需要的转换)包括"在运行时,首先对
重要的是,即使
这完全建立了新的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | namespace ConsoleApplication { class Test { private static int count = 0; public static object TestMethod() { count++; return null; } } class Program { static void Main(string[] args) { var test = Test.TestMethod() ?? new object(); } } } |
我刚刚写了这个测试应用程序。在运行test.testmethod()之后,它看起来只增加了一次,所以看起来它只被调用了一次,不管testmethod返回空值还是新对象。
第一个操作数只计算一次,在检查空值之前,不会将结果赋给变量。
第一个操作数被评估,然后检查是否为空。如果不为空,则它将成为表达式的值。如果为空,则计算第二个操作数并将其用作表达式的值。之后,将值赋给变量。
就好像使用了一个临时变量:
1 2 3 | int? temp = GetNullableInt(); if (!temp.HasValue) temp = default(int); int i = temp; |
我编写了这个简单的控制台应用程序,将
1 2 3 4 5 | static int Main( string[] args ) { int i = SomeHelpers.GetNullableInt() ?? default(int) ; return i ; } |
这是以不同方式生成的IL。您将注意到,在所有情况下,
1 | int i = GetNullableInt() ?? default(int) ; |
大致相当于
1 2 | int? t = GetNullableInt() ; int i = t.HasValue ? t.GetValueOrDefault() : 0 ; |
在我看来,生成的代码
我不知道,当这种情况发生时会发生什么。
这是MSIL:
Visual Studio 2010 SP1(调试):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25.method private hidebysig static int32 Main(string[] args) cil managed
{
.entrypoint
// Code size 33 (0x21)
.maxstack 2
.locals init ([0] int32 i,
[1] int32 CS$1$0000,
[2] valuetype [mscorlib]System.Nullable`1<int32> CS$0$0001)
IL_0000: nop
IL_0001: call valuetype [mscorlib]System.Nullable`1<int32> [SomeLibrary]SomeLibrary.SomeHelpers::GetNullableInt()
IL_0006: stloc.2
IL_0007: ldloca.s CS$0$0001
IL_0009: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_000e: brtrue.s IL_0013
IL_0010: ldc.i4.0
IL_0011: br.s IL_001a
IL_0013: ldloca.s CS$0$0001
IL_0015: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_001a: stloc.0
IL_001b: ldloc.0
IL_001c: stloc.1
IL_001d: br.s IL_001f
IL_001f: ldloc.1
IL_0020: ret
} // end of method Program::MainVisual Studio 2010 SP1(版本)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20.method private hidebysig static int32 Main(string[] args) cil managed
{
.entrypoint
// Code size 28 (0x1c)
.maxstack 2
.locals init ([0] int32 i,
[1] valuetype [mscorlib]System.Nullable`1<int32> CS$0$0000)
IL_0000: call valuetype [mscorlib]System.Nullable`1<int32> SomeLibrary]SomeLibrary.SomeHelpers::GetNullableInt()
IL_0005: stloc.1
IL_0006: ldloca.s CS$0$0000
IL_0008: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_000d: brtrue.s IL_0012
IL_000f: ldc.i4.0
IL_0010: br.s IL_0019
IL_0012: ldloca.s CS$0$0000
IL_0014: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: ret
} // end of method Program::MainVisual Studio 2013(调试)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26.method private hidebysig static int32 Main(string[] args) cil managed
{
.entrypoint
// Code size 34 (0x22)
.maxstack 1
.locals init ([0] int32 i,
[1] int32 CS$1$0000,
[2] valuetype [mscorlib]System.Nullable`1<int32> CS$0$0001)
IL_0000: nop
IL_0001: call valuetype [mscorlib]System.Nullable`1<int32> [SomeLibrary]SomeLibrary.SomeHelpers::GetNullableInt()
IL_0006: stloc.2
IL_0007: ldloca.s CS$0$0001
IL_0009: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_000e: brtrue.s IL_0013
IL_0010: ldc.i4.0
IL_0011: br.s IL_001a
IL_0013: ldloca.s CS$0$0001
IL_0015: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_001a: nop
IL_001b: stloc.0
IL_001c: ldloc.0
IL_001d: stloc.1
IL_001e: br.s IL_0020
IL_0020: ldloc.1
IL_0021: ret
} // end of method Program::MainVisual Studio 2013(版本)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20.method private hidebysig static int32 Main(string[] args) cil managed
{
.entrypoint
// Code size 28 (0x1c)
.maxstack 1
.locals init ([0] int32 i,
[1] valuetype [mscorlib]System.Nullable`1<int32> CS$0$0000)
IL_0000: call valuetype [mscorlib]System.Nullable`1<int32> [SomeLibrary]SomeLibrary.SomeHelpers::GetNullableInt()
IL_0005: stloc.1
IL_0006: ldloca.s CS$0$0000
IL_0008: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_000d: brtrue.s IL_0012
IL_000f: ldc.i4.0
IL_0010: br.s IL_0019
IL_0012: ldloca.s CS$0$0000
IL_0014: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
IL_0019: stloc.0
IL_001a: ldloc.0
IL_001b: ret
} // end of method Program::Main