为什么'''被实现为'as'?

Vin*_*vic 28 .net c# as-keyword

鉴于这是一个非常自然的用例(如果你不知道as实际上是什么),

if (x is Bar) {
   Bar y = x as Bar;
   something();
}
Run Code Online (Sandbox Code Playgroud)

实际上是等效的(也就是说,编译器生成的CIL来自上面的代码将是等价的):

Bar y = x as Bar;
if (y != null) {
    y = x as Bar; //The conversion is done twice!
    something();
}
Run Code Online (Sandbox Code Playgroud)

编辑:

我想我没有说清楚我的问题.我不会写第二个片段,因为它当然是多余的.我声称在编译第一个片段时编译器生成的CIL等同于第二个片段,这是多余的.问题:a)这是正确的吗?b)如果是这样,为什么这样is实施?

这是因为我发现第一个片段比实际写得更好更清晰,更漂亮

Bar y = x as Bar;
if (y != null) {
   something();
}
Run Code Online (Sandbox Code Playgroud)

结论:

优化is/ ascase不是编译器的责任,而是JIT的责任.

此外,与空检查它具有比这两个方案(较少(更便宜)的说明isasiscast).

附录:

与nullcheck一样的CIL(.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
Run Code Online (Sandbox Code Playgroud)

CIL for is和cast(.NET 3.5):

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
Run Code Online (Sandbox Code Playgroud)

CIL for is和as(.NET 3.5):

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
Run Code Online (Sandbox Code Playgroud)

这些已被编辑为简洁(方法声明,nops和删除的某些东西的调用).

Eri*_*ert 12

a)这是正确的吗?

是的,虽然我会以另一种方式说明.你是说"是"是一个后跟空检查的语法糖.我会用另一种方式说:"as"是"检查类型实现,如果成功则转换,如果失败则为null"的语法糖.

也就是说,我更倾向于说

if (x is Bar) { 
   Bar y = x as Bar; 
   something(); 
} 
Run Code Online (Sandbox Code Playgroud)

实际上相当于

if (x is Bar) { 
   Bar y = (x is Bar) ? (Bar)x : (Bar) null; 
   something(); 
} 
Run Code Online (Sandbox Code Playgroud)

看,你想用"是"来定义"as",而不是相反.问题应该是"为什么按原样实施?" :-)

b)如果是这样,为什么会这样实施?

因为这是规范的正确实现.

我想我不是在追随你的思路.这个实现有问题吗?您希望如何实施?您可以使用"isinst"和"castclass"说明; 描述您希望看到的程序的codegen.


Dam*_*ver 9

好吧,可用的IL指令(isinst)将返回相应类型的对象,如果无法进行此类转换,则返回null.如果转换不可能,它不会抛出异常.

鉴于此,"是"和"作为"都是微不足道的.在这种情况下,我不会声称"is"被实现为"as",只是底层IL指令允许两者都发生.现在,为什么编译器无法在单个isinst调用中优化"is"后跟"as",这是另一回事.可能,在这种情况下,它与变量范围有关(即使这是IL,范围实际上并不存在)

编辑

再想一想,您不能将"is"后跟"as"优化为单个isinst调用,而不知道所讨论的变量不会受到其他线程的更新.

假设x是一个字符串:

//Thread1
if(x is string)

//Thread2
x = new ComplexObject();

//Thread1
    y = x as string
Run Code Online (Sandbox Code Playgroud)

在这里,y应为null.

  • 只要变量不是易变的并且is和as之间没有障碍,就没有理由不重用第一个实例. (2认同)

Wil*_*den 5

在您的示例中,as无论如何使用都是多余的.既然你已经知道了x is Bar,你应该使用一个演员:

if (x is Bar)
{
    Bay y = (Bar)x;
}
Run Code Online (Sandbox Code Playgroud)

或者,转换使用as并只检查null:

Bar y = x as Bar;
if (y != null)
{

}
Run Code Online (Sandbox Code Playgroud)


Ste*_*eve 5

首先,我不同意你的前提,即这是更典型的用例.它可能是您最喜欢的方法,但惯用法是"as + null check"样式:

Bar y = x as Bar; 
if (y != null) { 
   something(); 
}
Run Code Online (Sandbox Code Playgroud)

正如您所发现的那样,"is"方法需要额外的"as"或强制转换,这就是为什么带"null"检查的"as"是我的经验中执行此操作的标准方法.

对于这种"as"方法,我没有看到任何令人反感的举动,我个人认为它不会比任何其他代码更令人不快.

至于你的实际问题,为什么is关键字实现as关键字,我不知道,但我确实喜欢你的问题中的文字游戏:)我怀疑实际上既没有实现另一个,而是工具(我猜想反射器)你曾经用IL生成C#来解释IL as.