【问题标题】:Is there a "HasNext" method for an IEnumerator?IEnumerator 是否有“HasNext”方法?
【发布时间】:2010-11-19 08:51:53
【问题描述】:

使用 Java Iterators,我使用了 hasNext 方法来确定迭代是否有更多元素(不消耗元素)——因此,hasNext 就像一个“Peek”方法。

我的问题:C# 的通用 IEnumerators 是否有类似“hasNext”或“Peek”的方法?

【问题讨论】:

标签: c# iterator ienumerator peek


【解决方案1】:

不可以,但是在 C# 中,您可以重复请求当前元素,而无需移动到下一个元素。这只是一种不同的看待方式。

编写一个 C# 类来采用 .NET 样式的 IEnumerator 并返回 Java 样式的 Iterator 并不难。就我个人而言,我发现 .NET 样式在大多数情况下更易于使用,但我们开始了 :)

编辑:好的,这完全未经测试,但我认为它会起作用。它至少可以编译:)

using System;
using System.Collections;
using System.Collections.Generic;

// // Mimics Java's Iterable<T> interface
public interface IIterable<T>
{
    IIterator<T> Iterator();
}

// Mimics Java's Iterator interface - but
// implements IDisposable for the sake of
// parity with IEnumerator.
public interface IIterator<T> : IDisposable
{
    bool HasNext { get; }
    T Next();
    void Remove();
}

public sealed class EnumerableAdapter<T> : IIterable<T>
{
    private readonly IEnumerable<T> enumerable;

    public EnumerableAdapter(IEnumerable<T> enumerable)
    {
        this.enumerable = enumerable;
    }

    public IIterator<T> Iterator()
    {
        return new EnumeratorAdapter<T>(enumerable.GetEnumerator());
    }
}

public sealed class EnumeratorAdapter<T> : IIterator<T>
{
    private readonly IEnumerator<T> enumerator;

    private bool fetchedNext = false;
    private bool nextAvailable = false;
    private T next;

    public EnumeratorAdapter(IEnumerator<T> enumerator)
    {
        this.enumerator = enumerator;
    }

    public bool HasNext
    {
        get
        {
            CheckNext();
            return nextAvailable;
        } 
    }

    public T Next()
    {
        CheckNext();
        if (!nextAvailable)
        {
            throw new InvalidOperationException();
        }
        fetchedNext = false; // We've consumed this now
        return next;
    }

    void CheckNext()
    {
        if (!fetchedNext)
        {
            nextAvailable = enumerator.MoveNext();
            if (nextAvailable)
            {
                next = enumerator.Current;
            }
            fetchedNext = true;            
        }
    }

    public void Remove()
    {
        throw new NotSupportedException();
    }

    public void Dispose()
    {
        enumerator.Dispose();
    }
}

public sealed class IterableAdapter<T> : IEnumerable<T>
{
    private readonly IIterable<T> iterable;

    public IterableAdapter(IIterable<T> iterable)
    {
        this.iterable = iterable;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return new IteratorAdapter<T>(iterable.Iterator());
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

public sealed class IteratorAdapter<T> : IEnumerator<T>
{
    private readonly IIterator<T> iterator;

    private bool gotCurrent = false;
    private T current;

    public IteratorAdapter(IIterator<T> iterator)
    {
        this.iterator = iterator;
    }

    public T Current
    {
        get
        {
            if (!gotCurrent)
            {
                throw new InvalidOperationException();
            }
            return current;
        }
    }

    object IEnumerator.Current
    {
        get { return Current; }
    }

    public bool MoveNext()
    {
        gotCurrent = iterator.HasNext;
        if (gotCurrent)
        {
            current = iterator.Next();
        }
        return gotCurrent;
    }

    public void Reset()
    {
        throw new NotSupportedException();
    }

    public void Dispose()
    {
        iterator.Dispose();
    }
}

【讨论】:

  • (如果有人感兴趣,我很乐意编写适配器,但否则我不会这样做......)
  • 乔恩,我很想看看。
  • 哇,真快!谢谢你,乔恩!
  • @Andrew,它的责任有点不同。我发现 dotNet 版本更易于使用。
  • Java 迭代器的主要缺点是它们没有 IDisposable 的等价物,这使得它们无法用于任何可能对资源进行迭代的东西(例如文件中的行)。
【解决方案2】:

不,很遗憾没有。

IEnumerator&lt;T&gt; 接口只公开以下成员:

方法:

Dispose
MoveNext
Reset

属性

Current

【讨论】:

  • 我们在这里使用 IEnumerator,而不是 IEnumerable,对吗?并且 * 应该在 Dispose 上,而不是 MoveNext。
  • @Even - 哎呀,那个帖子充满了错误!感谢您指出。
【解决方案3】:

枚举器经常被懒惰地评估,所以 HasNext 没有什么意义。

【讨论】:

    【解决方案4】:

    NopeMoveNextResetCurrent

    【讨论】:

      【解决方案5】:

      您也可以尝试查看此Implementing Peek to IEnumerator and IEnumerator<>。它是一种将 Peek 功能添加到 IEnumerator 的扩展方法。希望能帮助到你。 :)

      【讨论】:

        【解决方案6】:

        使用良好的旧手动迭代

                // IEnumerable<>
                for (int i = 0; i < enumerable.Count(); i++)
                {
                    var item = enumerable.ElementAt(i);
        
                    if(i + 1 < enumerable.Count()) // eq. Iterator.HasNext
                    {
                    }
                }
        
                // IList<>
                for (int i = 0; i < list.Count; i++)
                {
                    var item = list[1];
        
                    if (i + 1 < list.Count) // eq. Iterator.HasNext
                    {
                    }
                }
        

        【讨论】:

          猜你喜欢
          • 2016-04-25
          • 2011-03-04
          • 1970-01-01
          • 1970-01-01
          • 2011-07-05
          • 2023-03-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多