'is'与使用null check的try cast相比

Hot*_*otN 102 .net c# resharper casting

我注意到Resharper建议我转过身:

if (myObj.myProp is MyType)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

进入这个:

var myObjRef = myObj.myProp as MyType;
if (myObjRef != null)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

为什么会建议这种变化?我已经习惯了Resharper建议优化更改和代码减少更改,但这感觉就像它想要我的单一陈述并将其转换为双线程.

根据MSDN:

一个 表达式如果两个满足以下条件的值为true:

表达式不为空.表达式可以转换为类型.也就是说,表单的强制转换表达式将在(type)(expression)不抛出异常的情况下完成.

我是否误读了,或者没有is完全相同的检查,只需要在一行中而不需要为空检查显式创建另一个局部变量?

Jef*_*f E 137

因为只有一个演员.比较一下:

if (myObj.myProp is MyType) // cast #1
{
    var myObjRef = (MyType)myObj.myProp; // needs to be cast a second time
                                         // before using it as a MyType
    ...
}
Run Code Online (Sandbox Code Playgroud)

对此:

var myObjRef = myObj.myProp as MyType; // only one cast
if (myObjRef != null)
{
    // myObjRef is already MyType and doesn't need to be cast again
    ...
}
Run Code Online (Sandbox Code Playgroud)

C#7.0支持使用模式匹配的更紧凑的语法:

if (myObj.myProp is MyType myObjRef)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

  • 另请注意,原始版本不是线程安全的.`myObj`或`myProp`的值可以在`is`和强制转换之间(由另一个线程)改变,从而导致不良行为. (4认同)
  • 究竟.使用'is'基本上就像返回一样((myProp as MyType)== null) (3认同)
  • 就变化而言,这是非常微小的.空检查将与第二种类型检查相当.`as`可能会快几纳秒,但我认为这是一个过早的微优化. (2认同)

Fra*_*oni 8

最好的选择是使用模式匹配:

if (value is MyType casted){
    //Code with casted as MyType
    //value is still the same
}
//Note: casted can be used outside (after) the 'if' scope, too
Run Code Online (Sandbox Code Playgroud)


Jer*_*vel 6

目前还没有关于皮带下面究竟发生了什么的信息.看看这个例子:

object o = "test";
if (o is string)
{
    var x = (string) o;
}
Run Code Online (Sandbox Code Playgroud)

这转换为以下IL:

IL_0000:  nop         
IL_0001:  ldstr       "test"
IL_0006:  stloc.0     // o
IL_0007:  ldloc.0     // o
IL_0008:  isinst      System.String
IL_000D:  ldnull      
IL_000E:  cgt.un      
IL_0010:  stloc.1     
IL_0011:  ldloc.1     
IL_0012:  brfalse.s   IL_001D
IL_0014:  nop         
IL_0015:  ldloc.0     // o
IL_0016:  castclass   System.String
IL_001B:  stloc.2     // x
IL_001C:  nop         
IL_001D:  ret   
Run Code Online (Sandbox Code Playgroud)

这里重要的是isinstcastclass电话 - 两者都相对昂贵.如果将其与替代方案进行比较,您可以看到它只进行isinst检查:

object o = "test";
var oAsString = o as string;
if (oAsString != null)
{

}

IL_0000:  nop         
IL_0001:  ldstr       "test"
IL_0006:  stloc.0     // o
IL_0007:  ldloc.0     // o
IL_0008:  isinst      System.String
IL_000D:  stloc.1     // oAsString
IL_000E:  ldloc.1     // oAsString
IL_000F:  ldnull      
IL_0010:  cgt.un      
IL_0012:  stloc.2     
IL_0013:  ldloc.2     
IL_0014:  brfalse.s   IL_0018
IL_0016:  nop         
IL_0017:  nop         
IL_0018:  ret  
Run Code Online (Sandbox Code Playgroud)

另外值得一提的是,值类型将使用unbox.any而不是castclass:

object o = 5;
if (o is int)
{
    var x = (int)o;
}

IL_0000:  nop         
IL_0001:  ldc.i4.5    
IL_0002:  box         System.Int32
IL_0007:  stloc.0     // o
IL_0008:  ldloc.0     // o
IL_0009:  isinst      System.Int32
IL_000E:  ldnull      
IL_000F:  cgt.un      
IL_0011:  stloc.1     
IL_0012:  ldloc.1     
IL_0013:  brfalse.s   IL_001E
IL_0015:  nop         
IL_0016:  ldloc.0     // o
IL_0017:  unbox.any   System.Int32
IL_001C:  stloc.2     // x
IL_001D:  nop         
IL_001E:  ret   
Run Code Online (Sandbox Code Playgroud)

但请注意,这并不一定意味着更快的结果,我们可以在这里看到.目前似乎已经改善,因为该问题是尽管问:铸件看起来就像他们曾经是,但要快速执行aslinq现在大约快3倍.