2012-09-17 25 views
1

可能重複:
Is it possible to recreate this statement without using a foreach?嘗試轉換的foreach中的LINQ相當於

我有2個類共享一個基類

DealBookmarkWrapper : BookmarkWrapper 
StoreBookmarkWrapper : BookmarkWrapper 

我也有下面的語句:

// 1 - This works 
List<BookmarkWrapper> bm = new List<BookmarkWrapper>(); 
foreach(var d in deals) 
{ 
    bm.Add(new DealBookmarkWrapper(d)); 
} 

// 2 - This does not work 
List<BookmarkWrapper> bm2 = deals.Select(d => new DealBookmarkWrapper(d)).ToList(); 

1)工作原理但2需要演員工作。我不確定自己是在做錯事還是在第二種情況下真的需要演員陣容。

任何人都會對此有所瞭解?

+1

@Nacereddine:這不是該問題的重複,OP想知道*爲什麼*第二個解決方案不起作用。 – Ani

+0

這可以幫助你:[協方差和反變化](http://stackoverflow.com/questions/11186493/c-is-operator-for-generic-types-with-inheritance/11186567#11186567) –

回答

0

第二個場景需要轉換,因爲您的LINQ表達式投影到派生對象列表(List<DealBookmarkWrapper>)。然而,你想要的是創建一個基礎對象列表(List<BookmarkWrapper>)。由於您希望編譯器「丟失」某些類型信息,因此您需要明確說明它。

最好的解決辦法是.ToList調用之前插入Cast<BookmarkWrapper>,使這個明確的,並保持一個可讀的語法:

var bm2 = deals.Select(d => new DealBookmarkWrapper(d)) 
       .Cast<BookmarkWrapper>() 
       .ToList(); 
2
List<BookmarkWrapper> bm2 = deals.Select(d => new DealBookmarkWrapper(d)).Cast<BookmarkWrapper>().ToList(); 

或者

List<BookmarkWrapper> bm2 = deals.Select(d => (BookmarkWrapper)(new DealBookmarkWrapper(d))).ToList(); 

你的代碼創建一個List<DealBookmarkWrapper>,這是不可轉換爲List<BookmarkWrapper>。列表的類型由C#的類型推斷算法確定。

兩個選項都上面創建DealBookmarkWrapper對象,但鑄參照BookmarkWrapper,所以類型推斷解析類型List<BookmarkWrapper>代替。

7

您的問題是雙重的:

  • 類型參數的的ToList<T>T是由編譯器推斷爲DealBookmarkWrapper,所以List<DealBookmarkWrapper>被產生。
  • 由於List<T>不是協變類型,因此從List<DealBookmarkWrapper>到List<BookmarkWrapper>沒有任何表示保留轉換。有關更多信息,請參閱this question

您已經發現在Select投影中添加投射是一種解決方法。另一種方式,在C#4 + .NET 4.0(或更高版本)將是顯式地指定類型參數,依靠IEnumerable<T>協方差:

deals.Select(d => new DealBookmarkWrapper(d)) 
    .ToList<BookmarkWrapper>() 
+1

我想說「很好的解決方案「,但這本身並不足夠。 – phoog

+0

(Nitpick:C#4 + .NET 2.0就足夠了) – Timwi

+1

@Timwi:對於CLR支持也許,但不是IEnumerable '只在.NET 4.0中標記爲'out'的類型參數? – Ani

1

你沒有做錯什麼。 List<T>不是covariant所以你需要明確地轉換對象。更多信息here