2012-09-17 35 views
12

說,我們有2類:爲什麼Enumerable.Cast不使用用戶定義的強制轉換?

public class A 
{ 
    public int a; 
} 

public class B 
{ 
    public int b; 

    public static implicit operator B(A x) 
    { 
     return new B { b = x.a }; 
    } 
} 

那麼爲什麼

A a = new A { a = 0 }; 
B b = a; //OK 

List<A> listA = new List<A> { new A { a = 0 } }; 
List<B> listB = listA.Cast<B>().ToList(); //throws InvalidCastException 

同爲explicit運營商。

P.S。:手動澆鑄每個元素(separetely)的工作原理

List<B> listB = listA.Select<A, B>(s => s).ToList(); //OK 

回答

10

Enumerable.Cast名稱是誤導,因爲其目的是爲了拆箱值。它適用於IEnumerable而不是IEnumerable<T>)生成IEnumerable<T>。如果您已有IEnumerable<T>Enumerable.Cast很可能不是您想要使用的方法。

從技術上講,它是做這樣的事情:

foreach(object obj in value) 
    yield return (T)obj; 

如果T是東西比裝箱值否則,這將導致InvalidCastException

你可以自己測試此行爲:

int i = 0; 
object o = i; 
double d1 = (double)i; // Works. 
double d2 = (double)o; // Throws InvalidCastException 

你有兩種可能的解決方案:

  1. 使用Select(x => (B)x)
  2. 創建一個擴展方法Cast上的IEnumerable<T>而非IEnumerable工作。
+0

那麼,它是否會失敗,因爲它試圖將'object'強制轉換爲'B',而我從'A'到'B'定義了強制轉換? – horgh

+0

它失敗了,因爲它首先需要將「對象」取消到「A」,而不是演員。就像'(B)(A)o'。你也許可以定義一個在'object'而不是'A'上工作的轉換運算符,但是這並不合理,因爲大多數'object'實例都是不可轉換的。 –

+0

但是它是'List ',其中'T'是'A'。它不是'ArrayList'或'List '。爲什麼這個拳擊/拆箱問題發生? – horgh

相關問題