2011-02-07 14 views
100

可能重複:
Casting vs using the ‘as’ keyword in the CLRC# 「作爲」 劇組VS經典投

我最近學到了不同的方式來投。而不是使用

SomeClass someObject = (SomeClass) obj; 

一個可以使用這個語法:

SomeClass someObject = obj as SomeClass; 

這似乎返回null如果obj不是一個SomeClass的,而不是拋出一個類轉換異常。

我看到,如果轉換失敗並且我嘗試訪問someObject變量,這可能會導致NullReferenceException。所以我想知道這種方法的基本原理是什麼?爲什麼要使用這種鑄造方式而不是(舊的) - 它似乎只是將「失敗」的問題轉移到代碼中。

+1

相關和非常豐富:http://stackoverflow.com/questions/496096/casting-vs-using-the-as-keyword-in-the-clr/496167#496167 – JYelton 2011-02-07 22:14:33

+3

對這個問題進行更多的思考看到我關於這個問題的文章:http://blogs.msdn.com/b/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx – 2011-02-08 00:30:55

+0

http ://blogs.msdn.com/b/ericlippert/archive/2009/10/08/what-s-the-difference-between-as-and-cast-operators.aspx – 2014-03-31 16:24:09

回答

124

使用「經典」方法,如果轉換失敗,則拋出異常。使用as方法,它會導致null,它可以被檢查,並避免拋出異常。

此外,您只能對引用類型使用「as」,因此如果您將類型轉換爲值類型,則仍然必須使用「classic」方法。

注:

as方法只能用於可分配一個null值類型。這隻能用於表示引用類型,但是當.NET 2.0推出時,它引入了可爲空的值類型的概念。由於這些類型可以分配一個null值,因此它們可以與as運算符一起使用。

+9

此外,「經典」劇組可以執行轉換。 `as`只能做參考/裝箱轉換。 – 2011-02-07 21:20:26

+4

準確地說,你也可以使用「as」作爲'Nullable `類型(並且可爲空類型是值類型...) – digEmAll 2011-02-07 21:22:43

1

使用as將返回null,如果不是有效的轉換,它允許您在try/catch中包裝轉換之外執行其他操作。我討厭經典演員。如果我不確定,我總是會使用。另外,例外是昂貴的。空檢查不是。

27

空比較是很多比拋出和捕捉異常更快。例外情況有很大的開銷 - 堆棧跟蹤必須進行組裝等。

異常應該表示意外狀態,這通常不代表情況(當as工作更好時)。

0

這裏沒有什麼深層次的事情發生。基本上,測試某些東西是否屬於某種類型(即使用'as')很方便。你會想檢查'as'調用的結果來查看結果是否爲空。

如果您希望演員陣容能夠正常工作並且希望拋出異常,請使用'傳統'方法。

0

您使用「as」語句來避免發生例外情況,例如,您可以通過邏輯優雅地處理演員陣容失敗。只有在確定對象屬於所需類型時才使用投射。我幾乎總是使用「as」,然後檢查null。

24

在某些情況下,處理null比例外更容易。特別地,合併運算符是很方便的:

SomeClass someObject = (obj as SomeClass) ?? new SomeClass(); 

你在哪裏(不使用多態和支鏈)基於對象的類型,也簡化代碼:

ClassA a; 
ClassB b; 
if ((a = obj as ClassA) != null) 
{ 
    // use a 
} 
else if ((b = obj as ClassB) != null) 
{ 
    // use b 
} 

由於對指定MSDN page,所述as操作等效於:

expression is type ? (type)expression : (type)null 

這避免了完全有利於更快的類型測試的異常,但也限制我ts用於支持null(引用類型和Nullable<T>)的類型。

3

當你真的不知道該變量可能是什麼類型時,as關鍵字是有用的。如果您有將遵循根據實際類型參數的不同的代碼路徑的單一功能,那麼你有兩種選擇:

首先,使用普通投:

if(myObj is string) 
{ 
    string value = (string)myObj; 

    ... do something 
} 
else if(myObj is MyClass) 
{ 
    MyClass = (MyClass)myObj; 
} 

這需要你檢查使用is的對象的類型,以便您不要嘗試將其轉換爲會失敗的東西。這也有點多餘,因爲is類型檢查再次在演員陣列中完成(以便它可以在需要時拋出異常)。

另一種方法是使用as

string myString = myObj as string; 
MyClass myClass = myObj as MyClass; 

if(myString != null) 
{ 

} 
else if(myClass != null) 
{ 

} 

這使得代碼稍短並且還可以消除多餘的類型檢查。

1

我認爲最好的「規則」是隻使用「爲」當它的預期,您的問題將不會是你投射到物體關鍵字:

var x = GiveMeSomething(); 

var subject = x as String; 

if(subject != null) 
{ 
    // do what you want with a string 
} 
else 
{ 
    // do what you want with NOT a string 
} 

然而,當你的主題應該是你正在投射的類型,使用'經典演員',就像你說的那樣。因爲如果它不是你期望的類型,你會得到一個符合特殊情況的例外。

0

我想如果將轉換的結果傳遞給一個你知道將會處理空引用而不拋出和ArgumentNullException或類似的方法,那麼它是有用的。

我往往很少發現使用了as,因爲:

obj as T 

慢於:

if (obj is T) 
    ...(T)obj... 

採用as是非常對我來說是邊緣的情況下,使我想不出任何關於什麼時候使用它的通用規則,只是在堆棧中進一步處理(更多信息)的轉換異常。

5

as運算符在幾種情況下很有用。

  1. 當你只需要知道對象是特定的類型,但不需要該類型
  2. 成員特異性地作用。當你想避免的異常,而是明確地處理null
  3. 您想知道對象之間是否存在CLR轉換,而不僅僅是某些用戶定義的轉換。

第三點很微妙但很重要。在演員和演員之間沒有1-1映射,演員將通過as操作符成功。 as運算符嚴格限於CLR轉換,不會考慮用戶定義的轉換(演員操作符將會)。

具體地,操作者as只允許進行以下(從C#朗規範的部分7.9.11)

  • 的身份(第6.1.1節),隱式引用(第6.1.6節),拳擊(第6.1.7節)中,明確引用(第6.2.4節)或拆箱(第6.2.5節)轉換存在於E到T的類型。
  • E或T的類型是開放類型。
  • E是空字面。