【问题标题】:Interface implementations and return types接口实现和返回类型
【发布时间】:2012-01-06 21:43:44
【问题描述】:

List<T> 类实现了IEnumerable<T> 接口。它有一个方法GetEnumerator,返回一个List<T>.Enumerator

我有一个如下的类,它给出了一个编译错误,指出GetEnumerator 的返回类型与接口不匹配。

public class InsertionSortedSet<T> : IEnumerable<T>
{
    public struct Enumerator : IEnumerator<T>
    {
        // Required interface implemented
    }

    // Other interface methods implemented

    public Enumerator GetEnumerator()
    {
        return new Enumerator(this);
    }
}

“Entities.Helpers.InsertionSortedSet”没有实现接口成员“System.Collections.Generic.IEnumerable.GetEnumerator()”。 “Entities.Helpers.InsertionSortedSet.GetEnumerator()”无法实现“System.Collections.Generic.IEnumerable.GetEnumerator()”,因为它没有匹配的返回类型“System.Collections.Generic.IEnumerator”。

鉴于List&lt;T&gt; 似乎返回了它自己的Enumerator 类(不是接口),但它确实实现了Enumeration&lt;T&gt; 接口,我很困惑,因为我看不出我有什么不同那个班级。

我的设置有什么问题导致它失败,List&lt;T&gt; 在哪里工作?


我想返回 InsertionSortedSet&lt;T&gt;.Enumerator 而不是界面,因为它避免了装箱,我需要删除它。

【问题讨论】:

    标签: c# generics interface enumerator


    【解决方案1】:

    之所以抱怨是因为 GetEnumerator() 为 IEnumerable&lt;T&gt; 接口返回 IEnumerator&lt;T&gt;。为了满足要求,您的类型必须返回 IEnumerator&lt;T&gt;(以及一个明确的 IEnumerator)。

    但是,很多时候希望类返回比接口指定的更具体的类型,但接口不允许这样的协变返回类型。因此,要做到这一点,您可以执行 List&lt;T&gt; 所做的事情并让 GetEnumerator() 返回您的特定枚举器,但您还必须为返回 IEnumerator 和 @ 的 IEnumerable.GetEnumerator() 实现 explicit 实现987654330@ 返回一个IEnumerator&lt;T&gt;

        // This is your specific version, like List<T> does
        public Enumerator GetEnumerator()
        {
            return new Enumerator(this);
        }
    
        // This is the one with the return value IEnumerator<T> expects
        IEnumerator<T> IEnumerable<T>.GetEnumerator()
        {
            return new Enumerator(this);
        }
    
        // Plus, it also expects this as well to satisfy IEnumerable
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    

    如果您查看List&lt;T&gt;,您会发现它实现了GetEnumerator() 3 次:

    • 曾经明确表示IEnumerable&lt;T&gt;
    • 曾经明确表示Enumerable
    • 曾经有一个非常特定于列表的返回

    如果你愿意,你也可以在你的课堂上做同样的事情(它应该是你开始的方式),但如果你这样做,你必须明确地实现 IEnumerable&lt;T&gt;.GetEnumerator()IEnumerable.GetEnumerator()

    如果您导航到定义,您可以在对象浏览器中查看其他定义,方法是选择它满足的不同接口(或通过将List&lt;T&gt; 实例分配给IEnumerableIEnumerable&lt;T&gt; 引用并转到定义):

    【讨论】:

    • @GeogeDuckett:我在此基础上进行了更新。 List 实现了三次GetEnumerable(),一次使用它自己的特定于列表的枚举器,以及一个显式的IEnumerableIEnumerable&lt;T&gt;
    • 啊,我明白了。欺骗我的是右键单击List&lt;T&gt; 并选择Go to Definition 不会显示它。 GetEnumerator 的所有方法都去哪里看了?
    • @GeorgeDuckett:我使用反编译器查看 .NET Framework 程序集,不过您也可以在线获取 .NET 源代码。
    • 感谢您的回答。我完全忘记了对象浏览器。
    • @GeorgeDuckett:不用担心 :-) 我很惊讶 VS 中有很多很酷的东西,我有时会忘记......
    【解决方案2】:

    允许使用foreach 迭代一个类,无需实现任何接口。您所需要的只是实现返回您的 Enumerator&lt;T&gt; 的 GetEnumerator 方法。

    但如果你希望你的类支持标准迭代接口IEnumerable&lt;T&gt;,你可以明确地实现它:IEnumerable&lt;T&gt;.GetEnumerator() { return GetEnumerator(); }

    【讨论】:

    • 这对我的用例有所帮助,但问题仍然存在; List&lt;T&gt; 是如何实现接口的,据我所知,它做了我想做的事情(返回具体类型,而不是接口)。
    • public class List : IEnumerable { public struct Enumerator : IEnumerator { ... } public Enumerator GetEnumerator() { return ... } IEnumearator IEnumerable.GetEnumerator() { return GetEnumerator(); } }
    【解决方案3】:

    您正在寻找的称为返回类型协方差,更多信息请参见Does C# support return type covariance?

    这可以通过显式实现接口返回IEnumerator&lt;T&gt;并实现同名的公共方法返回Enumerator来实现。

    【讨论】:

      猜你喜欢
      • 2013-07-22
      • 2019-02-10
      • 2011-05-16
      • 2012-10-06
      • 1970-01-01
      • 2016-10-16
      • 1970-01-01
      • 1970-01-01
      • 2011-06-22
      相关资源
      最近更新 更多