鉴于这是一个非常自然的用例(如果您不知道as
实际做了什么),
if (x is Bar) {
Bar y = x as Bar;
something();
}
等效于(也就是说,编译器从上述代码生成的CIL将等效于):
Bar y = x as Bar;
if (y != null) {
y = x as Bar; //The conversion is done twice!
something();
}
编辑:
我想我没有把我的问题说清楚。我永远不会写第二个片段,因为它当然是多余的。我声称编译器在编译第一个片段时生成的 CIL 等同于第二个片段,这是多余的。问题: a) 这是正确的吗?b) 如果是这样,为什么要这样is
实施?
这是因为我发现第一个片段比实际写得好的片段更清晰、更漂亮
Bar y = x as Bar;
if (y != null) {
something();
}
结论:
优化is
/ as
case 不是编译器的职责,而是 JIT 的职责。
is
此外,与空检查一样,它比两种替代方法( andas
和is
and )具有更少(且成本更低)的指令cast
。
附录:
CIL 与 nullcheck (.NET 3.5) 一样:
L_0001: ldarg.1
L_0002: isinst string
L_0007: stloc.0
L_0008: ldloc.0
L_0009: ldnull
L_000a: ceq
L_000c: stloc.1
L_000d: ldloc.1
L_000e: brtrue.s L_0019
L_0011: ldarg.0
L_0019: ret
用于 is 和 cast (.NET 3.5) 的 CIL:
L_0001: ldarg.1
L_0002: isinst string
L_0007: ldnull
L_0008: cgt.un
L_000a: ldc.i4.0
L_000b: ceq
L_000d: stloc.1
L_000e: ldloc.1
L_000f: brtrue.s L_0021
L_0012: ldarg.1
L_0013: castclass string
L_0018: stloc.0
L_0019: ldarg.0
L_0021: ret
用于 is 和 as (.NET 3.5) 的 CIL:
L_0001: ldarg.1
L_0002: isinst string
L_0007: ldnull
L_0008: cgt.un
L_000a: ldc.i4.0
L_000b: ceq
L_000d: stloc.1
L_000e: ldloc.1
L_000f: brtrue.s L_0021
L_0012: ldarg.1
L_0013: isinst string
L_0018: stloc.0
L_0019: ldarg.0
L_0021: ret
为了简短起见,这些已被编辑(删除了方法声明、nops 和对某事()的调用)。