【发布时间】:2011-11-29 15:23:58
【问题描述】:
我有这样的功能:
DoSomething(List<IMyInterface>)
IMyInterface 是一个接口,而 MyClass 是一个实现该接口的类 类 MyClass:IMyInterface
我打电话给DoSomething(List<MyClass>),它看起来不起作用。
如何将类的列表作为函数的参数传递给类的接口列表?谢谢!
【问题讨论】:
我有这样的功能:
DoSomething(List<IMyInterface>)
IMyInterface 是一个接口,而 MyClass 是一个实现该接口的类 类 MyClass:IMyInterface
我打电话给DoSomething(List<MyClass>),它看起来不起作用。
如何将类的列表作为函数的参数传递给类的接口列表?谢谢!
【问题讨论】:
如果您的代码只是简单地迭代方法内的序列(而不是添加、删除或按索引访问),请将您的方法更改为以下之一
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<> 的方法。
【讨论】:
DoSomething<T>(IList<T> list) where T : IMyInterface 不也可以工作吗? (无需复制列表。)
这通常是不安全的,因为列表是可变的。假设您将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。
【讨论】:
如果您只需要遍历列表,请使用 IEnumerable 声明方法。如果您想向列表中添加元素,您所要求的不是类型安全的,因此在 C# 中可能不允许。
【讨论】: