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.

+6
source share
7 answers

Add the following explicit implementation of the interface:

 IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); } 

Although IEnumerator<T> is an IEnumerator , the contract for IEnumerable returns an IEnumerator , not an IEnumerator<T>

+12
source

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 } 
+5
source

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(); } 
+4
source

While the generic IEnumerable {T} inherit is IEnumerable, you must also implement IEnumerable.GetEnumerator() . You can do it explicitly:

 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } 
+2
source

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() { /* ... */ } 
+2
source

When you implement the general IEnumerable interface, you also need to implement the non-general IEnumerable interface. The error is due to a missing non-generic method.

0
source

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(); } 
0
source

Source: https://habr.com/ru/post/898865/


All Articles