67

特に、「public IEnumerator GetEnumerator()」メソッドを実装するインターフェイスがあるので、foreachステートメントでインターフェイスを使用できます。

このインターフェイスをいくつかのクラスに実装し、そのうちの1つで、空のIEnumeratorを返したいと思います。今、私はこれを次のようにしています:

public IEnumerator GetEnumerator()
{
    ArrayList arr = new ArrayList();
    return arr.GetEnumerator();
}

しかし、これは醜いハックだと思います。空のIEnumeratorを返すより良い方法があると思わずにはいられません。ある?

4

9 に答える 9

94

これはC#2では簡単です。

public IEnumerator GetEnumerator()
{
    yield break;
}

yield breakコンパイラにイテレータブロックとして処理させるためのステートメントが必要です。

これは「カスタム」の空のイテレータよりも効率的ではありませんが、コードは単純です...

于 2009-11-11T10:43:18.687 に答える
91

フレームワークには追加の機能があります。

public static class Enumerable
{
    public static IEnumerable<TResult> Empty<TResult>();
}

これを使用して、次のように書くことができます。

var emptyEnumerable = Enumerable.Empty<int>();
var emptyEnumerator = Enumerable.Empty<int>().GetEnumerator();
于 2010-03-17T11:24:41.200 に答える
13

IEnumeratorを実装するダミークラスを実装し、そのインスタンスを返すことができます。

class DummyEnumerator : IEnumerator
{
    public object Current
    {
        get
        {
            throw new InvalidOperationException();
        }
    }

    public bool MoveNext()
    {
        return false;
    }

    public void Reset()
    {
    }
}
于 2009-11-11T10:42:25.180 に答える
7

私は興味があり、もう少し進んだ。メソッドが比較している効率とカスタムクラスをチェックするテストを行いましyield breakEnumerable.Emtpy

dotnetfiddle https://dotnetfiddle.net/p5ZkUNで確認するか、以下のコードを使用してください。

190000回の反復を使用した多くのdotnetfiddle実行の1つの結果は次のとおりです。

イールドブレイク:00:00:00.0012208

Enumerable.Empty():00:00:00.0007815

EmptyEnumeratorインスタンス:00:00:00.0010226

using System;
using System.Diagnostics;
using System.Collections;
using System.Linq;
                    
public class Program
{
    private const int Iterations = 190000;
    public static void Main()
    {
        var sw = new Stopwatch();
        
        IEnumerator enumerator1 = YieldBreak();
        sw.Start();
        for (int i = 0; i < Iterations; i++)
        {
            while(enumerator1.MoveNext())
            {
                throw new InvalidOperationException("Should not occur");
            }           
        }
        sw.Stop();
        
        Console.WriteLine("Yield break: {0}", sw.Elapsed);
        
        GC.Collect();
        
        IEnumerator enumerator2 = Enumerable.Empty<object>().GetEnumerator();
        sw.Restart();
        for (int i = 0; i < Iterations; i++)
        {
            while(enumerator2.MoveNext())
            {
                throw new InvalidOperationException("Should not occur");
            }           
        }
        sw.Stop();
        
        Console.WriteLine("Enumerable.Empty<T>(): {0}", sw.Elapsed);
        
        GC.Collect();
        
        var enumerator3 = new EmptyEnumerator();
        sw.Restart();
        for (int i = 0; i < Iterations; i++)
        {
            while(enumerator3.MoveNext())
            {
                throw new InvalidOperationException("Should not occur");
            }           
        }
        sw.Stop();
        
        Console.WriteLine("EmptyEnumerator instance: {0}", sw.Elapsed);
    }
    
    public static IEnumerator YieldBreak()
    {
        yield break;
    }
    
    private class EmptyEnumerator : IEnumerator
    {
        //public static readonly EmptyEnumerator Instance = new EmptyEnumerator();
        
        public bool MoveNext()
        {
            return false;
        }
        
        public void Reset()
        {
        }
        
        public object Current { get { return null; } }
    }
}
于 2016-11-28T17:40:37.433 に答える
5

私が使用する方法は、空の配列の列挙子を使用することです。

public IEnumerator GetEnumerator() {
    return new object[0].GetEnumerator();
}

また、汎用IEnumeratorまたはIEnumerableにも使用できます(適切なタイプの配列を使用)

于 2009-11-11T10:53:19.647 に答える
1

IEnumeratorインターフェイスとIEnumerableを実装し、IEnumerableインターフェイスのMoveNext関数からfalseを返すことができます

private class EmptyEnumerator : IEnumerator
{


    public EmptyEnumerator()
    {
    }

    #region IEnumerator Members

    public void Reset() { }

    public object Current
    {
        get
        {
            throw new InvalidOperationException();
        }
    }
    public bool MoveNext()
    { return false; }
}


public class EmptyEnumerable : IEnumerable
{

    public IEnumerator GetEnumerator()
    {
        return new EmptyEnumerator();
    }
}
于 2009-11-11T10:39:00.037 に答える
1

私はそれをこのように書いた:

public IEnumerator<T> GetEnumerator()
{
    return this.source?.GetEnumerator() ??
            Enumerable.Empty<T>().GetEnumerator();
}
于 2015-11-27T12:43:28.827 に答える
0

IEnumeratorインターフェイスを実装するNullEnumeratorを作成できます。NullEnumeratorからインスタンスを渡すことができます。

これがEmptyEnumeratorの例です

于 2009-11-11T10:38:44.393 に答える
0

空の列挙子を取得する最も簡単な方法を探しているこの質問を見つけました。パフォーマンスを比較する答えを見た後、私は空の列挙子クラスのソリューションを使用することにしましたが、私のものは他の例よりもコンパクトで、ジェネリック型であり、デフォルトのインスタンスも提供するため、すべての新しいインスタンスを作成する必要はありません時間。これにより、パフォーマンスがさらに向上するはずです。

class EmptyEnumerator<T> : IEnumerator<T>
{
   public readonly static EmptyEnumerator<T> value = new EmptyEnumerator<T>();
   public T Current => throw new InvalidOperationException();
   object IEnumerator.Current => throw new InvalidOperationException();
   public void Dispose() { }
   public bool MoveNext() => false;
   public void Reset() { }
}
于 2017-12-03T17:26:13.947 に答える