2011-10-03 56 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#中使用。