2011-10-03 54 views
15

我有這樣的函數:如何將類列表傳遞給接口列表?

DoSomething(List<IMyInterface>) 

IMyInterface的是一個接口,MyClass的是實現了這個接口 MyClass類的類:IMyInterface的

我稱之爲DoSomething(List<MyClass>)和它看起來這是行不通的。 如何將類的列表作爲函數的參數傳遞給類的接口列表?謝謝!

+0

你的代碼是什麼? – talnicolas

回答

26

如果您的代碼簡單地遍歷序列的方法中(未添加,移除,或通過索引訪問),你的方法更改爲以下

DoSomething(IEnumerable<IMyInterface> sequence) 
DoSomething<T>(IEnumerable<T> sequence) where T : IMyInterface 

IEnumerable<>接口中的一個是協變(如.NET 4)(第一個選項)。或者如果使用C#3,則可以使用後者簽名。

否則,如果您需要索引操作,請在傳遞它之前轉換列表。在調用時,你可能有

// invocation using existing method signature 
DoSomething(yourList.Cast<IMyInterface>().ToList()); 

// or updating method signature to make it generic 
DoSomething<T>(IList<T> list) where T : IMyInterface 

什麼後簽名會允許你做的是還​​支持添加或(調用點可見)移除到列表中,並且它也將讓你使用列表而不首先複製它。即使如此,如果你所做的只是遍歷循環中的列表,我還是傾向於使用方法加入IEnumerable<>

+0

對於索引操作和刪除,不會'DoSomething (IList list)其中T:IMyInterface'也有效? (不需要複製列表) – millimoose

+0

@Sli,是的,他可以使該方法具有通用性。我已更新以顯示通用選項。 –

+0

另一種方法是定義一個接口IReadableList ,然後編寫一個包裝類,實現IList和IList 。不過,其他代碼不幸的是必須改變爲使用包裝類。人們可以定義一個從列表到ListWrapper 的擴大轉換,但是這會有點噁心,並且它不會幫助系統認識到List 可以變成實現IReadableList 的某種(ListWrapper )。 – supercat

7

這通常不安全,因爲列表是可變的。假設你通過一個人的List<MyClass>參考作爲List<IMyInterface>,然後他們這樣做:

void Foo(List<IMyInterface> list) 
{ 
    IMyInterface x = new MyOtherClassWhichAlsoImplementsIMyInterface(); 
    list.Add(x); 
} 

現在你List<MyClass>包含一個類,它是不是一個MyClass的實例。這會違反類型安全。 (正如其他答案所指出的那樣,您只需通過List的IEnumerable<>接口就可以避免此問題,該接口提供只讀訪問,因此安全)。

欲瞭解更多詳情,請參閱Using Variance in Interfaces for Generic Collections on MSDN。另見a good summary of covariance and contravariance and various C# features that support it

0

如果您只需要瀏覽列表,請使用IEnumerable聲明該方法。如果你想添加元素到列表中,你所要求的不是類型安全的,因此可能不允許在C#中使用。