質問
私は他のものの間で、「公共のIEnumerator GetEnumeratorメソッド()」メソッドを実装し、インタフェースを持っているので、私はforeach文でインターフェイスを使用することができます。
私はいくつかのクラスでは、このインタフェースを実装し、そのうちの一つで、私は空のIEnumeratorに返すようにしたいです。今、私はこれを次のように行います:
public IEnumerator GetEnumerator()
{
ArrayList arr = new ArrayList();
return arr.GetEnumerator();
}
しかし、私はこの醜いハックを検討し、私は助けるが、空のIEnumeratorの返還に良い方法があることを考えることはできません。ありますか?
解決
これは、C#2が単純です
public IEnumerator GetEnumerator()
{
yield break;
}
あなたは反復子ブロックとしてそれを治療するためのコンパイラを強制的にyield break
文を必要とする。
このは「カスタム」空のイテレータよりも効率になりますが、それは単純なコードです...
他のヒント
枠組みの中で、余分な機能があります:
public static class Enumerable
{
public static IEnumerable<TResult> Empty<TResult>();
}
あなたが書くことができ、これを使用します
var emptyEnumerable = Enumerable.Empty<int>();
var emptyEnumerator = Enumerable.Empty<int>().GetEnumerator();
あなたはのIEnumeratorを実装ダミークラスを実装し、そのインスタンスを返すことができます:
class DummyEnumerator : IEnumerator
{
public object Current
{
get
{
throw new InvalidOperationException();
}
}
public bool MoveNext()
{
return false;
}
public void Reset()
{
}
}
私は興味があったし、少しさらに行きました。私は方法がyield break
、Enumerable.Emtpy
とカスタムクラスを比較する方法を効率的にチェックするテストを行っています。
あなたはdotnetfiddle https://dotnetfiddle.net/vTkmcQ の上でそれをチェックアウトするか、以下のコードを使用することができます。
多くdotnetfiddleの一つの結果は、190 000回の反復をした使用して実行されます。
収量のブレーク:00:00:00.0210611
Enumerable.Empty():00:00:00.0192563
EmptyEnumeratorインスタンス:00:00:00.0012966
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();
sw.Start();
for (int i = 0; i < Iterations; i++)
{
IEnumerator enumerator = YieldBreak();
while(enumerator.MoveNext())
{
throw new InvalidOperationException("Should not occur");
}
}
sw.Stop();
Console.WriteLine("Yield break: {0}", sw.Elapsed);
GC.Collect();
sw.Restart();
for (int i = 0; i < Iterations; i++)
{
IEnumerator enumerator = Enumerable.Empty<object>().GetEnumerator();
while(enumerator.MoveNext())
{
throw new InvalidOperationException("Should not occur");
}
}
sw.Stop();
Console.WriteLine("Enumerable.Empty<T>(): {0}", sw.Elapsed);
GC.Collect();
sw.Restart();
var instance = new EmptyEnumerator();
for (int i = 0; i < Iterations; i++)
{
while(instance.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; } }
}
}
私が使用方法は、空の配列の列挙子を使用することである。
public IEnumerator GetEnumerator() {
return new object[0].GetEnumerator();
}
また、ジェネリックのIEnumeratorまたはIEnumerableを(適切なタイプのアレイを使用する)
のために使用することができますあなたはIEnumeratorインターフェイスとIEnumerableをを実装し、IEnumerableをinterfaseの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();
}
}
私はこのようにそれを書いた:
public IEnumerator<T> GetEnumerator()
{
return this.source?.GetEnumerator() ??
Enumerable.Empty<T>().GetEnumerator();
}
あなたはIEnumeratorインターフェイスを実装しNullEnumeratorを作ることができます。あなただけのNullEnumeratorオフインスタンスを渡すことができます。
EmptyEnumeratorの一例ですこの質問は空の列挙子を取得する最も簡単な方法を探しているが見つかりました。性能を比較答えを見た後、私は空の列挙クラスのソリューションを使用することにしましたが、鉱山は、他の例よりもコンパクトで、かつ一般的なタイプであり、また、あなたはすべての新しいインスタンスを作成する必要はありませんので、デフォルトのインスタンスを提供しますさらにパフォーマンスを向上させる必要がある時、ます。
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() { }
}