返回一个空的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 breakEnumerable.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(); }