71

I have an interface that, among other things, implements a "public IEnumerator GetEnumerator()" method, so I can use the interface in a foreach statement.

I implement this interface in several classes and in one of them, I want to return an empty IEnumerator. Right now I do this the following way:

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

However I consider this an ugly hack, and I can't help but think that there is a better way of returning an empty IEnumerator. Is there?

David Božjak
  • 16,887
  • 18
  • 67
  • 98

9 Answers9

100

This is simple in C# 2:

public IEnumerator GetEnumerator()
{
    yield break;
}

You need the yield break statement to force the compiler to treat it as an iterator block.

This will be less efficient than a "custom" empty iterator, but it's simpler code...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Note that this solution does not work in all cases - you cannot combine yield break with returning some other enumerator `if (some case) { yield break; } else { return SomeStaticMethodThatGivesEnumerable();} // does not work`. In that case, use the Empty option from the other solution. Thank you everyone involved. – Peter Kay Jun 16 '20 at 04:41
  • @PeterKay: But the question wasn't how to return an empty enumerator on a case where there's additional logic - it's how to return an empty enumerator when that's all the OP needs to do. If the question had been different, my answer would have been different too. – Jon Skeet Jun 16 '20 at 07:17
94

There is an extra function in the framework:

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

Using this you can write:

var emptyEnumerable = Enumerable.Empty<int>();
var emptyEnumerator = Enumerable.Empty<int>().GetEnumerator();
Richard Garside
  • 87,839
  • 11
  • 80
  • 93
user287107
  • 9,286
  • 1
  • 31
  • 47
13

You could implement a dummy class that implements IEnumerator, and return an instance of it:

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

    public bool MoveNext()
    {
        return false;
    }

    public void Reset()
    {
    }
}
Konamiman
  • 49,681
  • 17
  • 108
  • 138
8

I was curious and went a bit further. I made a test that checks how efficient the methods are comparing yield break, Enumerable.Emtpy and custom class.

You can check it out on dotnetfiddle https://dotnetfiddle.net/p5ZkUN or use the code below.

The result of one of the many dotnetfiddle runs using 190 000 iterations was:

Yield break: 00:00:00.0012208

Enumerable.Empty(): 00:00:00.0007815

EmptyEnumerator instance: 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; } }
    }
}
Santhos
  • 3,348
  • 5
  • 30
  • 48
  • What about creating an empty ArrayList/List and return its enumerator as the OP showed (ugly hack). Is it slower than the methods you measured here? – Damn Vegetables Jun 29 '20 at 14:53
  • 1
    You need to move the call to get the enumerator on the first two tests out of the loop as well, otherwise it's not a useful comparison. – matthias_buehlmann Aug 16 '20 at 11:43
6

The way I use is to use the enumerator of an empty array:

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

It can also be used for generic IEnumerator or IEnumerable (use an array of the appropriate type)

thecoop
  • 45,220
  • 19
  • 132
  • 189
1

You can implement IEnumerator interface and IEnumerable, and return false from MoveNext function of IEnumerable interfase

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();
    }
}
Arsen Mkrtchyan
  • 49,896
  • 32
  • 148
  • 184
  • According to MSDN documentation, Current should throw an exception in this case (http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.current.aspx) – Konamiman Nov 11 '09 at 10:47
1

I wrote it like this:

public IEnumerator<T> GetEnumerator()
{
    return this.source?.GetEnumerator() ??
            Enumerable.Empty<T>().GetEnumerator();
}
Johan Larsson
  • 17,112
  • 9
  • 74
  • 88
0

You can make a NullEnumerator which implements the IEnumerator interface. You can just pass an instance off the NullEnumerator.

here is an example of an EmptyEnumerator

Community
  • 1
  • 1
Ikke
  • 99,403
  • 23
  • 97
  • 120
0

Found this question looking for the simplest way to get an empty enumerator. After seeing the answer comparing performance I decided to use the empty enumerator class solution, but mine is more compact than the other examples, and is a generic type, and also provides a default instance so you don't have to create new instances all the time, which should even further improve performance.

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() { }
}
BlueMonkMN
  • 25,079
  • 9
  • 80
  • 146