2012-09-13 24 views
0

我有以下代碼:它是協變和逆變相關的問題嗎?

class Header<TItem> where TItem : IItem { IEnumerable<TItem> Item { get; set; } } 
class HeaderA : Header<ItemA> { public HeaderA(int a) {...} } 
class HeaderB : Header<ItemB> { public HeaderB(int b) {...} } 

interface IItem {...} 
class ItemA : IItem { } 
class ItemB : IItem { } 

public static List<Header<IItem>> list = new List<Header<IItem>> 
{ 
    new HeaderA(1) 
} 

編譯錯誤在最後new HeaderA(1)

Error 1 The best overloaded Add method 
'System.Collections.Generic.List<NS.Header<NS.IItem>>.Add(NS.Header<NS.IItem>)' 
for the collection initializer has some invalid arguments 

如何解決這個問題?

+0

'新的ItemA()'看起來不像它被調用。你的意思是'新HeaderA(1)'? – Brad

+0

@Brad謝謝。我糾正了。 – ca9163d9

回答

7

您正在嘗試將Header<ItemA>添加到List<Header<IItem>>。這需要從Header<ItemA>Header<IItem>的轉換 - 並且該轉換不存在。它不存在的一個很好的理由。試想一下,你的代碼是有效的......那麼這會工作:

List<Header<IItem>> list = ...; // As per code 
Header<IItem> header = list[0]; 
header.Item = new List<IItem>(); 

現在還記得header實際上一個HeaderA - 所以這個工作就相當於這個 HeaderA頭=新HeaderA(); header.Item = new List {new ItemB()};

這不是好當別的期望header.Item是一個IEnumerable<ItemA>(); - 所以應該沒問題:

ItemA itemA = header.Item.First(); 

...並明確不會,如果你已經在裏面添加了ItemB

基本上,你正在尋找通用的協方差 - 但你只能聲明在接口和委託(而不是在類如Header<TItem>),只有當類型參數不是在輸入位置使用它在這裏歸功於Item二傳手。

也許更重要的是,你的設計看起來非常複雜 - 我強烈懷疑如果你退後一步,你可以設計你的方式試圖做到這一點。

+0

謝謝,你能否詳細說明「退一步」? – ca9163d9

+0

@NickW:恩,我們不知道這裏的大圖 - 爲什麼你有這些類型。看看你是否可以完成相同的更大目標*無需*協變。 –

+0

本來我只有標題和項目。後來我發現還有其他的類與HeaderA和ItemA類似,只有很小的差別。所以Header和Item成爲HeaderA,HeaderB,...和ItemA,ItemB,... – ca9163d9