为什么IEnumerable <t>被定义为IEnumerable <out t =“”>,而不是IEnumerable <t> </t> </out> </t>

时间:2012-09-14 12:25:29

标签: c# linq c#-4.0

  

可能重复:
  Why was IEnumerable<T> made covariant in C# 4?

我正在MSDN查看IEnumerable<T>接口定义,并看到:

public interface IEnumerable<out T> : IEnumerable

我想知道为什么T被定义为out,为什么不呢?

public interface IEnumerable<T> : IEnumerable

这是什么原因?

4 个答案:

答案 0 :(得分:21)

可以找到更多信息here

out使类型参数协变。也就是说,您可以使用类型或任何派生类型。请注意,out仅对泛型有这种方式,在方法签名中使用它时有不同的含义(尽管您可能已经知道)。

以下是referenced page

中的示例
// 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关键字,您将无法执行此操作,因为类型会有所不同。

您可以阅读有关协方差(以及相关的逆变)here的更多信息。

正如其他答案所指出的那样,IEnumerable仅在.NET 4中变为协变。试图编写如下代码:

IEnumerable<Object> strings = new List<string>();

将在.NET 4及更高版本中编译,但在以前的版本中不会编译。

答案 1 :(得分:6)

Covariance.这允许为集合分配比其通用参数中指定的更具体或派生类型的项。

IEnumerable<T>并不总是协变的;这是.NET 4的新功能,解释了here的原因。

答案 2 :(得分:6)

out类型参数说明符表示协方差。

在实践中,

如果我定义了两个接口。

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?)

这是因为协变接口允许更多的派生实例,而标准接口则没有。

Fiddle Here

答案 3 :(得分:0)

实现这一目标:

class Base {}
class Derived : Base {}

List<Derived> list = new List<Derived>();
IEnumerable<Base> sequence = list;