我在浏览MSDN的IEnumerable<T>
接口定义时发现:
可能是重复问题:
为什么在C# 4中将IEnumerable<T>协变?
public interface IEnumerable<out T> : IEnumerable
我在想为什么T被定义为
out
,而不是其他。public interface IEnumerable<T> : IEnumerable
这是什么原因?
我在浏览MSDN的IEnumerable<T>
接口定义时发现:
可能是重复问题:
为什么在C# 4中将IEnumerable<T>协变?
public interface IEnumerable<out T> : IEnumerable
out
,而不是其他。public interface IEnumerable<T> : IEnumerable
更多信息可以在这里找到。
out
使类型参数协变,也就是说,你可以使用该类型或任何派生类型。注意,out
只在泛型中以这种方式工作,在方法签名中使用时意义不同(尽管您可能已经知道这一点)。
这里是从引用页面中提取的例子:
// Covariant interface.
interface ICovariant<out R> { }
// Extending covariant interface.
interface IExtCovariant<out R> : ICovariant<R> { }
// Implementing covariant interface.
class Sample<R> : ICovariant<R> { }
class Program
{
static void Test()
{
ICovariant<Object> iobj = new Sample<Object>();
ICovariant<String> istr = new Sample<String>();
// You can assign istr to iobj because
// the ICovariant interface is covariant.
iobj = istr;
}
}
正如你所看到的,接口签名中的 out
允许你将 ICovariant<String>
赋值给 ICovariant<Object>
变量,因为 String
是从 Object
派生而来的。如果没有 out
关键字,你将无法这样做,因为类型会不同。
关于协变性(以及相关的逆变性),你可以在这里阅读更多信息。
正如其他答案所指出的一样,在 .NET 4 中才使 IEnumerable
成为协变。尝试编写以下代码是行不通的:
IEnumerable<Object> strings = new List<string>();
这段代码可以在 .NET 4 及以后的版本中编译通过,但无法在之前的版本中编译通过。
out
类型参数说明符表示协变。
< p > 实际应用中,
< p > 如果我定义了两个接口。
interface ISomeInterface<T>
{
}
interface ISomeCovariantInterface<out T>
{
}
class SomeClass<T> : ISomeInterface<T>, ISomeCovariantInterface<T>
{
}
接下来我尝试编译这段代码,
ISomeCovariantInterface<object> covariant = new SomeClass<string>(); // works
ISomeInterface<object> invariant = new SomeClass<string>(); // fails
// Cannot implicitly convert type 'SomeClass<string>' to 'ISomeInterface<object>'.
// An explicit conversion exists (are you missing a cast?)
class Base {}
class Derived : Base {}
List<Derived> list = new List<Derived>();
IEnumerable<Base> sequence = list;