返回一个空的IEnumerator
我有一个接口,除其他外,实现了“公共IEnumerator GetEnumerator()”方法,所以我可以在foreach语句中使用接口。
我在几个类中实现了这个接口,并且在其中一个类中,我想返回一个空的IEnumerator。 现在我按照以下的方式来做这件事:
public IEnumerator GetEnumerator() { ArrayList arr = new ArrayList(); return arr.GetEnumerator(); }
然而,我认为这是一个丑陋的黑客,我不禁认为有一个更好的方式返回一个空的IEnumerator。 在那儿?
在C#2中这很简单:
public IEnumerator GetEnumerator() { yield break; }
您需要yield break
语句来强制编译器将其视为迭代器块。
这将比“自定义”空迭代器效率更低,但它更简单的代码…
框架中还有一个额外的function:
public static class Enumerable { public static IEnumerable<TResult> Empty<TResult>(); }
你可以写
var NullEnumerable = Enumerable.Empty<int>();
您可以实现一个实现IEnumerator的虚拟类,并返回它的一个实例:
class DummyEnumerator : IEnumerator { public object Current { get { throw new InvalidOperationException(); } } public bool MoveNext() { return false; } public void Reset() { } }
我使用的方式是使用空数组的枚举数:
public IEnumerator GetEnumerator() { return new object[0].GetEnumerator(); }
它也可以用于通用IEnumerator或IEnumerable(使用适当types的数组)
我很好奇,并进一步。 我做了一个testing,检查方法比较yield break
, Enumerable.Emtpy
和自定义类的效率。
您可以在dotnetfiddle https://dotnetfiddle.net/vTkmcQ上查看或使用下面的代码。;
使用190 000次迭代的许多dotnetfiddle之一的结果是:
收益率突破: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; } } } }
您可以实现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(); } }
你可以创build一个实现IEnumerator接口的NullEnumerator。 你可以只传递一个NullEnumerator实例。
这里是一个EmptyEnumerator的例子
我是这样写的:
public IEnumerator<T> GetEnumerator() { return this.source?.GetEnumerator() ?? Enumerable.Empty<T>().GetEnumerator(); }