C# - 为什么在实现 IEnumerable 接口时实现两个版本的 Current

本文关键字:实现 两个 版本 Current 为什么 IEnumerable 接口 | 更新日期: 2023-09-27 17:55:27

我假设以下示例提供了我们在实现 IEnumerable 接口时应遵循的最佳实践。

https://learn.microsoft.com/en-us/dotnet/api/system.collections.ienumerator.movenext

问题是:

  1. 为什么我们应该提供两个版本的当前方法?
  2. 何时使用版本 ONE(对象 IEnumerator.Current)?
  3. 何时使用版本TWO(公共人员当前)?
  4. 如何在 foreach 语句中使用 PeopleEnum。
public class PeopleEnum : IEnumerator
{
    public Person[] _people;
    // Enumerators are positioned before the first element
    // until the first MoveNext() call.
    int position = -1;
    public PeopleEnum(Person[] list)
    {
        _people = list;
    }
    public bool MoveNext()
    {
        position++;
        return (position < _people.Length);
    }
    public void Reset()
    {
        position = -1;
    }
    // explicit interface implementation
    object IEnumerator.Current /// **version ONE**
    {
        get
        {
            return Current;
        }
    }
    public Person Current     /// **version TWO**
    {
        get
        {
            try
            {
                return _people[position];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }
}

C# - 为什么在实现 IEnumerable 接口时实现两个版本的 Current

IEnumerator.Current是一个显式接口实现。

仅当将迭代器转换为IEnumerator时,才能使用它(这是框架对foreach所做的)。在其他情况下,将使用第二个版本。

您将看到它返回object并且实际上使用返回Person的另一个实现。

接口本身不需要第二个实现,但为了方便起见,为了返回预期的类型而不是object

不再需要 IEnumerator 的长格式实现:

public class PeopleEnum : IEnumerable
{
    public Person[] _people;
    public PeopleEnum(Person[] list)
    {
        _people = list;
    }
    public IEnumerator GetEnumerator()
    {
        foreach (Person person in _people)
            yield return person;
    }
}

为了进一步将其带入 21 世纪,请不要使用非通用的 IEnumerable:

public class PeopleEnum : IEnumerable<Person>
{
    public Person[] _people;
    public PeopleEnum(Person[] list)
    {
        _people = list;
    }
    public IEnumerator<Person> GetEnumerator()
    {
        foreach (Person person in _people)
            yield return person;
    }
    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

我怀疑原因是这个代码示例是从实现IEnumerator<T>的示例类派生的 - 如果示例类PeopleEnum IEnumerator<T>实现的,则需要这种方法:IEnumerator<T>继承IEnumerator因此您必须在实现IEnumerator<T>时实现这两个接口。

非泛型IEnumerator的实现需要Current返回对象 - 另一方面,强类型IEnumerator<T>要求 Current 返回类型 T 的实例 - 使用显式和直接接口实现是满足这两个要求的唯一方法。

它是为了方便,例如。 在一段时间(p.MoveNext())循环中以类型安全的方式使用PeopleEnum.Current,而不是显式执行foreach枚举。

但是

您唯一需要做的就是实现接口,如果您愿意,您可以隐式执行此操作,但是有原因吗?如果我想在课堂上使用 MovePrior?如果我应该将对象投射(拆箱)给人会很酷吗?

如果你认为这个类可以用更多的操作方法来扩展,那么Person Current是一件很酷的事情。

版本二不是界面的一部分。您必须满足接口要求。