68

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
  • 15,855
  • 16
  • 66
  • 97

9 Answers9

94

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,335,956
  • 823
  • 8,931
  • 9,049
  • 4
    It's really pointless to try to compete with you in a C# question. :-) – Konamiman Nov 11 '09 at 10:49
  • 12
    @Konamiman: Not at all. Remember the LINQ question you answered and then deleted, spotting that the value of the attribute was required? I missed that! – Jon Skeet Nov 11 '09 at 10:54
  • 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
91

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
  • 85,699
  • 10
  • 79
  • 86
user287107
  • 9,046
  • 1
  • 29
  • 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
  • 48,742
  • 16
  • 110
  • 136
7

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,209
  • 4
  • 27
  • 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
5

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
  • 44,124
  • 18
  • 127
  • 185
  • I kinda like this solution. It's simple. It's straighforward. It's economic. It's elegant (at least by the looks of it). I'm wondering if there's any drawback to using something like this. Still, would buy again. – XDS May 13 '15 at 12:07
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
  • 48,710
  • 31
  • 147
  • 181
  • 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
  • 16,394
  • 9
  • 71
  • 85
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
  • 95,379
  • 23
  • 93
  • 119
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
  • 24,307
  • 9
  • 78
  • 139