Warning does not implement the 'collection' pattern

I am making collection, implementing IEnumerable explicitly and trying to iterate it from within:

public class MyCollection<T> : IEnumerable<T>, IEnumerable
{
    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
    IEnumerator<T> GetEnumerator() { yield return default(T); } // test

    public void Test()
    {
        foreach (var item in this) { } // here is warning
    }
}

I get compiler warning at this:

Warning CS0279 'MyCollection' does not implement the 'collection' pattern. 'MyCollection.GetEnumerator()' is either static or not public.

Hell yes, it's not public. Why it should be? I can make it public, but it's not needed for foreach outside of type:

foreach (var item in new MyCollection<string>()) { } // no warning

Am I doing something wrong?

Jon Skeet
people
quotationmark

The warning exists because the C# compiler can handle foreach in a number of different ways. One of those ways is to find a GetEnumerator method with a suitable return type. That's checked before the compiler checks whether or not the type of the expression implements IEnumerable or IEnumerable<T>.

In your case, it gets as far as finding the single parameterless GetEnumerator method, but it's not public. The C# specification recommends a warning at this point, as you may well have intended it to be usable for foreach. From the C# 5 spec, section 8.8.4, emphasis mine:

  • Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.

Any of the following would solve the problem:

  • Rename GetEnumerator to GetEnumeratorImpl or similar:

    IEnumerator IEnumerable.GetEnumerator() => GetEnumeratorImpl();
    IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumeratorImpl();
    IEnumerator<T> GetEnumeratorImpl() { yield return default(T); }
    
  • Don't use explicit interface implementation for IEnumerable<T>.GetEnumerator() - put the implementation there

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
    public IEnumerator<T> GetEnumerator() => { yield return default(T); }
    
  • Put the implementation in IEnumerable<T>.GetEnumerator, but cast this to IEnumerable<T> in IEnumerable.GetEnumerator to call it:

    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<T>) this).GetEnumerator();
    IEnumerator<T> IEnumerable<T>.GetEnumerator() => { yield return default(T); }
    

people

See more on this question at Stackoverflow