7

我有一个实现IEnumerator<string>. 见下文:

public class MyClass : IEnumerator<string>
{
    public bool MoveNext()
    {
        //....
    }

    //Implement other required methods....

   //Confusion lies below:
   public string Current { get { return this.CurrentLine; } }

   //Why do I need to implement IEnumerator.Current?!  In my tests, it's not even called    during my iteration
   object IEnumerator.Current { get { throw new NotImplementedException(); } }

}   

IEnumerator<T>除了接口和IEnumerator接口(继承)上都存在 .Current 属性这一事实之外IEnumerator<T>,实现它的意义何在?如上所示,它甚至没有被调用。

4

3 回答 3

17

IEnumerator<T>实现IEnumerator,所以在最基本的层面上你必须履行合同。

具体到为什么 - 如果有人这样做会发生什么:

((IEnumerator)yourInstance).Current

他们(通常)应该期望获得从IEnumerator<T>的实现返回的相同值/引用的松散类型副本。所以在大多数情况下,只需返回this.Current,不要担心它:)

(仅供参考——返回this.Current也是一种很好的做法,因为它遵循 DRY 和 SRP——让 Current 的强类型版本处理 Current 实际的实现细节。)

于 2011-03-02T18:56:27.407 回答
3

原因是IEnumerator<T>继承IEnumerator,所以当你从IEnumerator<T>你继承时也隐式地继承自 IEnumerator。如果您宣传一个接口,即使您从未打算使用它,您也应该为该接口提供一个实现。

于 2011-03-02T18:58:08.450 回答
1

编译器要求您实现所有虚拟程序,因为它不可能知道当某些未预料到的程序集在未知的未来某个时间点加载您的程序集时将调用哪些虚拟程序。通过从接口继承,您正在“签署合同”,承诺您将实现其所有成员。编译器要求您遵守该协议,以便其他程序集能够依赖它。

接口功能的目的是使您的类能够在任何地点、任何时间告诉任何其他程序集,“这是你可以要求我做的”。如果您想宣传较小的功能,请定义一个仅提供您想要的部分功能的新接口,然后实现它。

当然,所有这些都是工业强度的东西。它比您现在需要的代码要多。但 C# 旨在用于做严肃的事情,而不仅仅是玩具。

至于两个不同的,几乎相同的覆盖:您必须覆盖两个 Current 属性,因为它们本质上是不同的:一个是通用的返回 T;另一个是非泛型返回对象。您始终可以将 String 引用视为对 Object 的引用,但这并不是双向的。那么值类型呢?T 不限于是一个类。当然,编译器可以假设性地为您解决所有这些问题,并在两者可以替代的情况下让您摆脱困境,但事实并非如此,而且我不相信它应该这样做。如果你想要 C++,你知道在哪里可以找到它。

于 2011-03-02T19:04:07.253 回答