【问题标题】:Why IEnumerable<T> is defined as IEnumerable<out T>, not IEnumerable<T> [duplicate]为什么 IEnumerable<T> 被定义为 IEnumerable<out T>,而不是 IEnumerable<T> [重复]
【发布时间】:2012-09-14 12:25:28
【问题描述】:

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

我正在查看MSDNIEnumerable&lt;T&gt; 接口定义,然后查看:

public interface IEnumerable<out T> : IEnumerable

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

public interface IEnumerable<T> : IEnumerable

这是什么原因?

【问题讨论】:

标签: c# linq c#-4.0


【解决方案1】:

更多信息可以在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&lt;String&gt; 分配给ICovariant&lt;Object&gt; 变量,因为String 派生自Object。如果没有 out 关键字,您将无法执行此操作,因为类型会有所不同。

您可以阅读更多关于协变(以及相关的逆变)here

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

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

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

【讨论】:

    【解决方案2】:

    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

    【讨论】:

    • +1 我认为这是最清晰的入门级答案。
    【解决方案3】:

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

    IEnumerable&lt;T&gt; 并不总是协变的;这是 .NET 4 的新功能,更改的原因在 here 进行了解释。

    【讨论】:

      【解决方案4】:

      要实现这一点:

      class Base {}
      class Derived : Base {}
      
      List<Derived> list = new List<Derived>();
      IEnumerable<Base> sequence = list;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多