问题
I'm trying to create a wrapper for a 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 interface member 'System.Collections.IEnumerable.GetEnumerator()'. 'FooCollection.GetEnumerator()' cannot implement 'System.Collections.IEnumerable.GetEnumerator()' because it does not have the matching return type of 'System.Collections.IEnumerator'.
However I don't understand this error, because FooCollection.GetEnumerator()
returns an IEnumerator<Foo>
, and IEnumerator<Foo>
is an IEnumerator
.
EDIT:
The solution of explicitly implementing IEnumerator.GetEnumerator()
works. However I'm now wondering why when I "Go to definition" on a List<T>
I see only one definition of GetEnumerator:
public List<T>.Enumerator GetEnumerator();
Apparently List<T>
can have a single GetEnumerator
method that returns something that implements both IEnumerator<T>
and IEnumerator
, but I have to have one method for each?
EDIT:
As answered by LukeH below, List<T>
does include the explicit interface implementations. Apparently Visual Studio just doesn't list those when generating method stubs from the metadata. (See this previous question: Why does the VS Metadata view does not display explicit interface implemented members )
Before posting this question I had tried checking List<T>
(via "Go to Definition" in Visual Studio) to see if I needed to implement multiple versions of GetEnumerator. I guess this wasn't the most reliable way to check.
Anyway, I'm marking this as answered. Thanks for your help.
回答1:
Add the following explicit interface implementation:
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
Although IEnumerator<T>
is an IEnumerator
, the contract for IEnumerable
returns an IEnumerator
specifically, not an IEnumerator<T>
回答2:
When implementing IEnumerable<T>
, you must also explicitly implement IEnumerable.GetEnumerator()
. The method for the generic interface is not valid in and of itself as an implementation for the non-generic method contract. You can have one call the other, or since you have a child object whose enumerator 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
}
回答3:
The problem is that 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 have to implement the non-generic version explicitly:
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:
As long as generic IEnumerable{T} inherit IEnumerable You have to implement IEnumerable.GetEnumerator()
as well. You can do it explicitly like:
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
回答5:
You've already had several answers to your main question. I'll answer the question raised in your edit...
The List<T>
class actually has three different GetEnumerator
methods: The public method that's called when the compile-time instance is typed as List<T>
itself, and two explicit interface implementations to meet the IEnumerable
/IEnumerable<T>
contracts. The enumerator objects returned by all three methods are all the same List<T>.Enumerator
type 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() { /* ... */ }
回答6:
When you implement the generic IEnumerable interface, you also have to implement the non generic IEnumerable interface. The error is about the missing non generic method.
回答7:
Here's the declaration of IEnumerable:
public interface IEnumerable<out T> : IEnumerable
{
new IEnumerator<T> GetEnumerator();
}
notice the new keyword.
Here's the declaration of IEnumerable:
public interface IEnumerable
{
IEnumerator GetEnumerator();
}
So now you have a GetEnumerator method, but which one of those 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();
}
来源:https://stackoverflow.com/questions/7692455/how-do-i-implement-ienumerable-in-my-dictionary-wrapper-class-that-implements-ie