Null-Conditional 运算符是否在连续使用站点之间进行了优化,还是会导致重复检查?
Is the Null-Conditional operator optimized across consecutive usages sites or does it result in duplicate checks?
是否使用空条件运算符重复空检查?例如
var x = instance?.Property1;
var y = instance?.Property2;
是否编译成这个:
if (instance != null)
{
var x = instance.Property1;
var y = instance.Property2;
}
还是这个?
if (instance != null)
{
var x = instance.Property1;
}
if (instance != null)
{
var y = instance.Property2;
}
如果是前者,如果两行之间还有其他代码,会有什么不同吗?换句话说,compiler/optimizer有多聪明?
编译器似乎对此一无所知。
代码:
var x = instance?.Property1;
var y = instance?.Property2;
...编译为 non-optimized 为:
IL_0000: nop
IL_0001: newobj UserQuery+Class..ctor
IL_0006: stloc.0 // instance
IL_0007: ldloc.0 // instance
IL_0008: brtrue.s IL_000D
IL_000A: ldnull
IL_000B: br.s IL_0013
IL_000D: ldloc.0 // instance
IL_000E: ldfld UserQuery+Class.Property1
IL_0013: stloc.1 // x
IL_0014: ldloc.0 // instance
IL_0015: brtrue.s IL_001A
IL_0017: ldnull
IL_0018: br.s IL_0020
IL_001A: ldloc.0 // instance
IL_001B: ldfld UserQuery+Class.Property2
IL_0020: stloc.2 // y
IL_0021: ret
Class..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: ret
...并优化为:
IL_0000: newobj UserQuery+Class..ctor
IL_0005: dup
IL_0006: dup
IL_0007: brtrue.s IL_000C
IL_0009: pop
IL_000A: br.s IL_0012
IL_000C: ldfld UserQuery+Class.Property1
IL_0011: pop
IL_0012: dup
IL_0013: brtrue.s IL_0017
IL_0015: pop
IL_0016: ret
IL_0017: ldfld UserQuery+Class.Property2
IL_001C: pop
IL_001D: ret
Class..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret
两个分支检查都清楚。
在您的案例中,它使用 null 条件运算符执行两个单独的 If..Else 检查赋值。下面是反汇编的示例代码
源代码:
public class nulltest
{
public void test()
{
var instance = new testclass();
var x = instance?.prop1;
var y = instance?.prop2;
}
}
public class testclass
{
public int prop1;
public int prop2;
}
反汇编代码(ILSpy):
public class nulltest
{
public void test()
{
testclass testclass = new testclass();
if (testclass == null)
{
int? arg_20_0 = null;
}
else
{
new int?(testclass.prop1);
}
if (testclass == null)
{
int? arg_3A_0 = null;
}
else
{
new int?(testclass.prop2);
}
}
}
我使用 int
作为 属性 的类型,但以上内容适用于任何其他情况。
编译器严谨,想想这段代码
class Tricky
{
public int Property1
{
get
{
Program.instance = null;
return 1;
}
}
public int Property2
{
get
{
return 2;
}
}
}
class Program
{
public static Tricky instance = new Tricky();
public static void Main(string[] arg)
{
var x = instance?.Property1;
var y = instance?.Property2;
//what do you think the values of x,y
}
}
预期结果是:x == 1, y is null
。但是如果编译器使用一个 if
语句优化代码,它会抛出一个 NullReferenceException
。这意味着,使用一个 if
语句不是智能优化,它不是优化,因为它是错误的。
是否使用空条件运算符重复空检查?例如
var x = instance?.Property1;
var y = instance?.Property2;
是否编译成这个:
if (instance != null)
{
var x = instance.Property1;
var y = instance.Property2;
}
还是这个?
if (instance != null)
{
var x = instance.Property1;
}
if (instance != null)
{
var y = instance.Property2;
}
如果是前者,如果两行之间还有其他代码,会有什么不同吗?换句话说,compiler/optimizer有多聪明?
编译器似乎对此一无所知。
代码:
var x = instance?.Property1;
var y = instance?.Property2;
...编译为 non-optimized 为:
IL_0000: nop
IL_0001: newobj UserQuery+Class..ctor
IL_0006: stloc.0 // instance
IL_0007: ldloc.0 // instance
IL_0008: brtrue.s IL_000D
IL_000A: ldnull
IL_000B: br.s IL_0013
IL_000D: ldloc.0 // instance
IL_000E: ldfld UserQuery+Class.Property1
IL_0013: stloc.1 // x
IL_0014: ldloc.0 // instance
IL_0015: brtrue.s IL_001A
IL_0017: ldnull
IL_0018: br.s IL_0020
IL_001A: ldloc.0 // instance
IL_001B: ldfld UserQuery+Class.Property2
IL_0020: stloc.2 // y
IL_0021: ret
Class..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: nop
IL_0007: ret
...并优化为:
IL_0000: newobj UserQuery+Class..ctor
IL_0005: dup
IL_0006: dup
IL_0007: brtrue.s IL_000C
IL_0009: pop
IL_000A: br.s IL_0012
IL_000C: ldfld UserQuery+Class.Property1
IL_0011: pop
IL_0012: dup
IL_0013: brtrue.s IL_0017
IL_0015: pop
IL_0016: ret
IL_0017: ldfld UserQuery+Class.Property2
IL_001C: pop
IL_001D: ret
Class..ctor:
IL_0000: ldarg.0
IL_0001: call System.Object..ctor
IL_0006: ret
两个分支检查都清楚。
在您的案例中,它使用 null 条件运算符执行两个单独的 If..Else 检查赋值。下面是反汇编的示例代码
源代码:
public class nulltest
{
public void test()
{
var instance = new testclass();
var x = instance?.prop1;
var y = instance?.prop2;
}
}
public class testclass
{
public int prop1;
public int prop2;
}
反汇编代码(ILSpy):
public class nulltest
{
public void test()
{
testclass testclass = new testclass();
if (testclass == null)
{
int? arg_20_0 = null;
}
else
{
new int?(testclass.prop1);
}
if (testclass == null)
{
int? arg_3A_0 = null;
}
else
{
new int?(testclass.prop2);
}
}
}
我使用 int
作为 属性 的类型,但以上内容适用于任何其他情况。
编译器严谨,想想这段代码
class Tricky
{
public int Property1
{
get
{
Program.instance = null;
return 1;
}
}
public int Property2
{
get
{
return 2;
}
}
}
class Program
{
public static Tricky instance = new Tricky();
public static void Main(string[] arg)
{
var x = instance?.Property1;
var y = instance?.Property2;
//what do you think the values of x,y
}
}
预期结果是:x == 1, y is null
。但是如果编译器使用一个 if
语句优化代码,它会抛出一个 NullReferenceException
。这意味着,使用一个 if
语句不是智能优化,它不是优化,因为它是错误的。