How to implement IEnumerable in my Dictionary wrapper class that implements IEnumerable <Foo>?
I am trying to create a wrapper for Dictionary<String,Foo>
.
Dictionary<String,Foo>
implements IEnumerable<KeyValuePair<String,Foo>>
, but I want my wrapper class to implement IEnumerable<Foo>
. So I tried this:
public class FooCollection : IEnumerable<Foo> { private Dictionary<string, Foo> fooDictionary = new Dictionary<string, Foo>(); public IEnumerator<Foo> GetEnumerator() { return fooDictionary.Values.GetEnumerator(); } // Other wrapper methods omitted }
However, I get this error:
'FooCollection' does not implement a member of the 'System.Collections.IEnumerable.GetEnumerator ()' interface. 'FooCollection.GetEnumerator ()' cannot implement 'System.Collections.IEnumerable.GetEnumerator ()' because it does not have the corresponding return type 'System.Collections.IEnumerator'.
However, I do not understand this error because FooCollection.GetEnumerator()
returns IEnumerator<Foo>
, and IEnumerator<Foo>
returns IEnumerator
.
EDIT:
A solution explicitly implementing IEnumerator.GetEnumerator()
works. However, now I wonder why, when I "Go to Definition" on List<T>
, I see only one GetEnumerator definition: public List<T>.Enumerator GetEnumerator();
Apparently, List<T>
may have a single GetEnumerator
method that returns something that implements both IEnumerator<T>
and IEnumerator
, but should there be one method for each of them?
EDIT:
As LukeH answered below, List<T>
includes explicit interface implementations. Apparently, Visual Studio just doesn't list them when creating labels from metadata. (See Previous question: Why VS interface metadata view does not display explicit interface elements implemented in the interface )
Before posting this question, I tried checking List<T>
(via "Go to Definition" in Visual Studio) to see if I need to implement multiple versions of GetEnumerator. I think this was not the most reliable way to check.
Anyway, I mark this as an answer. Thank you for your help.
When implementing IEnumerable<T>
you must also explicitly implement IEnumerable.GetEnumerator()
. The method for the general interface is not valid as an implementation for a non-standard contract. You can call one another, or since you have a child whose counter you are using, just copy / paste;
using System.Collections; using System.Collections.Generic; public class FooCollection : IEnumerable<Foo> { private Dictionary<string, Foo> fooDictionary = new Dictionary<string, Foo>(); public IEnumerator<Foo> GetEnumerator() { return fooDictionary.Values.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { //forces use of the non-generic implementation on the Values collection return ((IEnumerable)fooDictionary.Values).GetEnumerator(); } // Other wrapper methods omitted }
The problem is that in .NET there is no such thing as return type covariance in .NET - IEnumerator M()
and IEnumerator<Foo> M()
are completely different methods.
The workaround is that you must explicitly implement the non-generic version:
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { // this calls the IEnumerator<Foo> GetEnumerator method // as explicit method implementations aren't used for method resolution in C# // polymorphism (IEnumerator<T> implements IEnumerator) // ensures this is type-safe return GetEnumerator(); }
While the generic IEnumerable {T} inherit is IEnumerable, you must also implement IEnumerable.GetEnumerator()
. You can do it explicitly:
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
You already had several answers to your main question. I will answer the question raised in your editing ...
The List<T>
class actually has three different GetEnumerator
methods: a public method that is called when a compilation time instance is entered as a List<T>
, and two explicit interface implementations for matching IEnumerable
/ IEnumerable<T>
contracts. The enumeration objects returned by all three methods are still of type List<T>.Enumerator
behind the scenes.
// Public method public List<T>.Enumerator GetEnumerator() { /* ... */ } // IEnumerable<T> explicit interface implementation IEnumerator<T> IEnumerable<T>.GetEnumerator() { /* ... */ } // IEnumerable explicit interface implementation IEnumerator IEnumerable.GetEnumerator() { /* ... */ }
Here is the IEnumerable declaration:
public interface IEnumerable<out T> : IEnumerable { new IEnumerator<T> GetEnumerator(); }
Pay attention to the new keyword.
Here is the IEnumerable declaration:
public interface IEnumerable { IEnumerator GetEnumerator(); }
So now you have the GetEnumerator method, but which of these two are you implementing? Therefore, you need to add an explicit implementation of the non-generic version:
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }