Question

I was curious to see how the SingleOrFallback method was implemented in MoreLinq and discovered something I hadn't seen before:

    public static T SingleOrFallback<T>(this IEnumerable<T> source, Func<T> fallback)
    {
        source.ThrowIfNull("source");
        fallback.ThrowIfNull("fallback");
        using (IEnumerator<T> iterator = source.GetEnumerator())
        {
            if (!iterator.MoveNext())
            {
                return fallback();
            }
            T first = iterator.Current;
            if (iterator.MoveNext())
            {
                throw new InvalidOperationException();
            }
            return first;
        }
    }

Why is the IEnumerator<T> in a using statement? Is this something that should be thought about when using the foreach on an IEnumerable<T> also?

Side question: What does this method do exactly? Does it return the fallback item whenever the source sequence does not contain exactly one item?

Was it helpful?

Solution

IEnumerator<T> extends IDisposable, so you should have it in a using statement. foreach does this automatically. (The non-generic IEnumerator doesn't extend IDisposable but the C# compiler still generates code to call Dispose conditionally. This was one of the (few) changes between C# 1.0 and 1.2, where 1.2 is the version shipping with .NET 1.1, for some reason.)

Here's an article explaining why this is important in the context of iterator blocks.

As for what the method does:

  • If the sequence is empty, return the fallback item
  • If the sequence has exactly one item, return it
  • If the sequence has more than one item, throw an exception

PS: Nice to see MoreLinq is getting some attention :)

OTHER TIPS

Some enumerators will behave badly if Dispose is not called; this is just as true for the non-generic ones as the generic ones (the non-generic ones require that code either duck-type the Dispose call or else cast to IDisposable and then call IDisposable.Dispose). It is good as a matter of habit to ensure that IEnumerator objects get disposed; I would consider it necessary for correctness of any routine which accepts an IEnumerable of unknown type.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top