c# - usage - vb net control




'是'與嘗試使用空檢查進行投射 (5)

我注意到Resharper建議我這樣做:

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

進入這個:

var myObjRef = myObj.myProp as MyType;
if (myObjRef != null)
{
   ...
}

它為什麼會提出這種改變? 我習慣了Resharper建議優化改變和代碼縮減的改變,但是這感覺就像它想要採用我的單一語句並將它變成雙線程。

根據MSDN

如果滿足以下兩個條件, 表達式的計算結果為true:

表達式不為null。 表達式可以轉換為類型 。 也就是說,表單(type)(expression)強製(type)(expression)將在不拋出異常的情況下完成。

我是否誤讀了這些,或者沒有做完全相同的檢查,只需一行,而不需要為空檢查顯式創建另一個局部變量?


Resharper警告:

"Type check and direct cast can be replaced with try cast and check for null"

兩者都可以工作,這取決於你的代碼更適合你。 在我的情況下,我忽略了這個警告:

//1st way is n+1 times of casting
if (x is A) ((A)x).Run();
else if (x is B) ((B)x).Run();
else if (x is C) ((C)x).Run();
else if (x is D) ((D)x).Run();
//...
else if (x is N) ((N)x).Run();    
//...
else if (x is Z) ((Z)x).Run();

//2nd way is z times of casting
var a = x as Type A;
var b = x as Type B;
var c = x as Type C;
//..
var n = x as Type N;
//..
var z = x as Type Z;
if (a != null) a.Run();
elseif (b != null) b.Run();
elseif (c != null) c.Run();
...
elseif (n != null) n.Run();
...
elseif (x != null) x.Run();

在我的代碼中,第二種方式是性能越來越差。


因為只有一個演員。 比較一下:

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
    ...
}

對此:

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

C#7.0使用模式匹配支持更緊湊的語法:

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

對我而言,這似乎取決於它是否屬於那種類型的可能性。 如果大部分時間對象屬於這種類型,那麼最好先進行一下。 如果僅僅是那種類型的話,那麼首先用is檢查可能是更優的。

與類型檢查的成本相比,創建局部變量的成本是微不足道的。

可讀性和範圍對我來說通常是更重要的因素。 我不同意ReSharper,僅僅因為這個原因使用“is”操作符; 如果這是一個真正的瓶頸,那麼稍後優化。

(我假設你只在這個函數中使用myObj.myProp is MyType


我會說這是為了創建myObj.myProp的強類型版本,它是myObjRef。 這應該在塊中引用此值時使用,而不必執行強制轉換。

例如,這個:

myObjRef.SomeProperty

比這更好:

((MyType)myObj.myProp).SomeProperty

目前還沒有關於皮帶下面究竟發生了什麼的信息。 看看這個例子:

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

這轉換為以下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   

這裡重要的是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  

另外值得一提的是,一個值類型將使用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   

但請注意,這不一定意味著更快的結果,因為我們可以here看到。 雖然這個問題被問到似乎有所改善:演員似乎執行速度與以前一樣快,但現在和linq現在快了大約3倍。





resharper