'is' versus try cast with null check

后端 未结 7 697
情歌与酒
情歌与酒 2020-12-08 03:28

I noticed that Resharper suggests that I turn this:

if (myObj.myProp is MyType)
{
   ...
}

into this:

var myObjRef = myObj.         


        
7条回答
  •  死守一世寂寞
    2020-12-08 04:17

    There's no information yet about what actually happens below the belt. Take a look at this example:

    object o = "test";
    if (o is string)
    {
        var x = (string) o;
    }
    

    This translates to the following 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   
    

    What matters here are the isinst and castclass calls -- both relatively expensive. If you compare that to the alternative you can see it only does an isinst check:

    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  
    

    Also worth mentioning is that a value type will use unbox.any rather than 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   
    

    Note however that this not necessarily translates to a faster result as we can see here. There seem to have been improvements since that question was asked though: casts seem to be performed as fast as they used to be but as and linq are now approximately 3 times faster.

提交回复
热议问题