我正在MSDN上查看IEnumerable<T>接口定义,并看到:
public interface IEnumerable<out T> : IEnumerable
Run Code Online (Sandbox Code Playgroud)
我想知道为什么T被定义为out,为什么不呢?
public interface IEnumerable<T> : IEnumerable
Run Code Online (Sandbox Code Playgroud)
这是什么原因?
Dan*_*iel 21
更多信息可以在这里找到.
在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;
}
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,out在接口签名允许您将分配ICovariant<String>给一个ICovariant<Object>变量,String从派生Object.如果没有out关键字,您将无法执行此操作,因为类型会有所不同.
正如其他答案所指出的那样,IEnumerable只在.NET 4中进行了协变.试图编写如下代码:
IEnumerable<Object> strings = new List<string>();
Run Code Online (Sandbox Code Playgroud)
将在.NET 4及更高版本中编译,但在以前的版本中不会编译.
所述out类型参数符表示协方差.
在实践中,
如果我定义两个接口.
interface ISomeInterface<T>
{
}
interface ISomeCovariantInterface<out T>
{
}
Run Code Online (Sandbox Code Playgroud)
然后,我像这样实现它们.
class SomeClass<T> : ISomeInterface<T>, ISomeCovariantInterface<T>
{
}
Run Code Online (Sandbox Code Playgroud)
然后我尝试编译这段代码,
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?)
Run Code Online (Sandbox Code Playgroud)
这是因为协变接口允许更多派生实例,而标准接口则不允许.