2012-12-17 98 views
1

我想在C#中做類似於協變的東西,但我沒有任何繼承。列表<Ttype>到列表<TInterface>在C#中?

我有這樣的代碼:

public interface IBirthday 
{ 
    void Dance(); 
} 


public class Birthday:IBirthday 
{ 
public void Dance() 
    {} 
} 


void Main() 
{ 
    List<Birthday> l= new List<Birthday>(); 
    List<IBirthday> d = l; //<--- How can I accomplish that ? 
} 

我怎樣才能使這項工作? (除了迭代和手動構建(linq或循環))

List<IBirthday> d = list of birthdays ? 

不會迭代/ linq是唯一的選擇嗎?

+3

你試過[''Cast'](http://msdn.microsoft.com/zh-cn/library/bb341406.aspx)? – Oded

+6

你不能也不應該,因爲缺乏協變性,它不是類型安全的。你應該可以做'IEnumerable d = 1;'雖然。 – millimoose

+0

你爲什麼想要一個'List '?這是關鍵,用例看起來很小。 –

回答

6

這不是可能分配一個List<Birthday>List<IBirthday>而無需創建一個全新的列表(可以從你被隱藏,但它必須某處發生)。

如果你試圖做是可能的,然後如果有人做會發生什麼:

public class UnBirthday : IBirthday { ... } 

d.Add(new UnBirthday()); 

嗯,這是一個List<IBirthday>,所以它認爲它能夠添加新的項目。但底層列表實際上是List<Birthday>,您不能將UnBirthday添加到該列表中。考慮到允許這個並在運行時崩潰的選擇,C#決定(正確地說,在我看來)首先不允許它。

使用通用參數協方差的唯一方法就是將其分配給只能讀取信息並且不會放入信息的東西。其中一個示例是IEnumerable<T>。每一個BirthdayIBirthday,而且也沒有辦法爲IEnumerable給予的IBirthday這不是一個Birthday,所以他說:

List<Birthday> l= new List<Birthday>(); 
IEnumerable<IBirthday> d = l; 

的作品就好了。

+0

構建一個'ReadOnlyListWrapper '將是可能的,其中U:T'將會包裝一個'IList '並執行'IList ',並且報告自己爲只讀。這樣的東西將不能在原始列表中存儲「T」,但會呈現列表的「實時」視圖,並且不需要複製它。 – supercat

+0

@supercat這將是我在最後一節中介紹的內容,它只是協變接口的另一個例子。 (你可以在.NET 4中使用'IReadOnlyList'。5,它可以像'IEnumerable'一樣工作於'List'或一個數組)。 – Servy

+0

我的觀點是,即使沒有任何內置類來這樣做,我們可以輕鬆地編寫一個包裝類這將允許'IList '被用作'IList '(允許單個項目被讀取,「通過索引實況」),而不僅僅是'IEnumerable '。 – supercat

3

您可以使用:

d = l.Cast<IBirthday>.ToList(); 
+4

這不是將新視圖分配到現有列表,而是創建一個全新的列表。這可能會或可能不會在語義上是你想要的。 – Servy

+0

我寫了沒有迭代(niether linq) –

+0

@Servy真的,我沒有考慮到這一點。我不知道你是如何解決這個問題的,雖然 – TheEvilPenguin