2009-10-15 88 views
5

考慮以下幾點:IEnumerable的<T>轉換


class Base<T> {/*...*/} 
class Der<T>: Base<T> {/*...*/} 

interface Sth<T>{ 
    IEnumerable<Base<T>> Foo {get;} 
} 

// and implementation... 
class Impl<T>: Sth<T> { 
    public IEnumerable<Base<T>> Foo { 
    get { 
     return new List<Der<T>>(); 
    } 
    } 
} 

我如何能得到這個編譯?很顯然,錯誤並不是從列表< Der < T >>到列表<基址< T >>中發現的隱式轉換。如果我明確強制轉換,則發生InvalidCastException。

+4

如果是你,你可能想要看我特別發達的一系列關於這項功能的C#4.0設計這個話題的興趣:http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+ Contravariance/default.aspx – 2009-10-15 03:36:13

回答

6

從.NET Framework 3.5版開始,您嘗試進行的轉換不受支持。由於增加了generic covariance/contravariance,它將在版本4.0(Visual Studio 2010)中得到支持。雖然這仍然不允許你投List<Der>List<Base>,但它允許您將IEnumerator<Der>(列表實現)轉換爲IEnumerator<Base>

在此期間,您可以編寫自己的類,它實現IEnumerable<Base>,並返回一個自定義IEnumerator<Base>簡單地包裝List<Der>IEnumerator<Der>。或者,如果您使用.NET Framework 3.5版,則可以像其他人所建議的那樣使用Cast extension method

+1

請注意,通用方差不允許將列表轉換爲列表,因爲列表同時具有類型T的成員和成員。(它*將*用於在適當位置使用IEnumerable 的IEnumerable 。) – itowlson 2009-10-15 01:05:15

+0

是的,但是,如果我理解正確,它將允許OP的代碼示例進行編譯。'列表'實現'IEnumerable ',它可以轉換爲'IEnumerable '。 – bcat 2009-10-15 01:08:09

+0

當然,我相信,我只提到它,因爲在問題文本中他提到了列表類型之間的隱式轉換,所以我想澄清一下,您的評論適用於他的代碼(使用IEnumerable),而不是他的補充評論(引用List)。 – itowlson 2009-10-15 01:16:18

1

爲了讓編譯...

class Impl<T> : Sth<T> 
{ 
    public IEnumerable<Base<T>> Foo 
    { 
     get 
     { 
      return new List<Base<T>>(); //change the List type to Base here 
     } 
    } 
} 

你總是可以做這樣的事情太多,這會從明鏡的實現返回基類的IEnumerable的

class Impl<T> : Sth<T> 
{ 
    public IEnumerable<Base<T>> Foo 
    { 
     get 
     { 
      List<Der<T>> x = new List<Der<T>>(); 

      foreach (Der<T> dt in x) 
      { 
       yield return dt; 
      } 
     } 
    } 
} 
4

List<Der<T>>是不可轉換爲List<Base<T>>,因爲後者可以添加Base<T>,前者不能。

爲此,可以使用Cast擴展方法解決:return new List<Der<T>>().Cast<Base<T>>();

1

您可以使用LINQ通過使用從List<Der<T>>強制轉換爲IEnumerable<Base<T>>,

class Impl<T>: Sth<T> 
{ 
    public IEnumerable<Base<T>> Foo 
    { 
     get 
     { 
      return new List<Der<T>>().Cast<Base<T>>(); 
     } 
    } 
} 

至於其他的答案已經指出,通用convariance是不支持在v3.5,但你可以使用LINQ創建一個包裝對象,實現IEnumerable<Base<T>>.

+0

謝謝,這有幫助。 演員會減慢應用程序的速度多少?它是否對性能產生重大影響? – SOReader 2009-10-15 14:01:27

+0

拿出秒錶,嘗試幾百萬次,然後你就會知道。您是唯一可以訪問應用程序的計時數據的人;我們無法回答這個問題。 – 2009-10-15 14:10:13

+0

放輕鬆,埃裏克=]只是問他是否檢查過的開銷... – SOReader 2009-10-15 18:51:51

0

這些答案幫了我,我只是想發佈我的解決我遇到的類似問題。

我寫了IEnumerable的擴展方法,每當我想要一個List <富>轉化爲一個IEnumerable <酒吧>(我仍然在3.5),其自動轉換TSource。

public static SpecStatus Evaluate<TSource, TSpecSource>(this IEnumerable<TSource> source, ISpec<IEnumerable<TSpecSource>> spec) 
     where TSource : TSpecSource 
{ 
    return spec.Evaluate(source.Cast<TSpecSource>()); 
} 
相關問題