如何在实现IEnumerable的Dictionary包装类中实现IEnumerable ?

本文关键字:IEnumerable 实现 Dictionary 包装类 Foo | 更新日期: 2023-09-27 18:10:47

我正在尝试为Dictionary<String,Foo>创建一个包装器。

Dictionary<String,Foo>实现IEnumerable<KeyValuePair<String,Foo>>,但我希望我的包装器类实现IEnumerable<Foo>。所以我试着这样做:

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
}

但是我得到这个错误:

'FooCollection'没有实现接口成员'System.Collections.IEnumerable.GetEnumerator()'。'FooCollection.GetEnumerator()'无法实现'System.Collections.IEnumerable.GetEnumerator()',因为它没有与'System.Collections.IEnumerator'匹配的返回类型。

但是我不理解这个错误,因为FooCollection.GetEnumerator()返回IEnumerator<Foo>,而IEnumerator<Foo>IEnumerator

编辑:

显式实现IEnumerator.GetEnumerator()的解决方案有效。然而,我现在想知道为什么当我在List<T>上"去定义"时,我只看到GetEnumerator的一个定义:public List<T>.Enumerator GetEnumerator();

显然List<T>可以有一个单一的GetEnumerator方法,返回实现IEnumerator<T>IEnumerator的东西,但我必须有一个方法为每个?

编辑:

正如LukeH在下面回答的,List<T> 确实包含显式接口实现。显然,Visual Studio在从元数据生成方法存根时没有列出这些。(参见前面的问题:为什么VS元数据视图不显示显式接口实现的成员)

张贴这个问题之前,我曾尝试检查List<T>(通过"去定义"在Visual Studio),看看我是否需要实现多个版本的GetEnumerator。我想这不是最可靠的检查方法。

不管怎样,我把这个标记为回答。谢谢你的帮助。

如何在实现IEnumerable<Foo>的Dictionary包装类中实现IEnumerable ?

添加以下显式接口实现:

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

虽然IEnumerator<T>IEnumerator,但IEnumerable的契约返回的是IEnumerator,而不是IEnumerator<T>

在实现IEnumerable<T>时,还必须显式地实现IEnumerable.GetEnumerator()。泛型接口的方法本身作为非泛型方法契约的实现是无效的。你可以让一个调用另一个,或者因为你有一个子对象,你正在使用它的枚举器,所以只需要复制/粘贴;

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
}

问题是。net中没有返回类型协方差这样的东西——IEnumerator M()IEnumerator<Foo> M()是完全不同的方法。

解决方法是必须显式地实现非泛型版本:

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

只要通用IEnumerable{T}继承IEnumerable你也必须实现IEnumerable.GetEnumerator()。您可以显式地这样做:

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

对于你的主要问题,你已经有了几个答案。我将回答你在编辑中提出的问题……

List<T>类实际上有三个不同的GetEnumerator方法:当编译时实例被类型为List<T>本身时调用的公共方法,以及满足IEnumerable/IEnumerable<T>契约的两个显式接口实现。这三个方法返回的枚举器对象在幕后都是相同的List<T>.Enumerator类型。

// Public method
public List<T>.Enumerator GetEnumerator() { /* ... */ }
// IEnumerable<T> explicit interface implementation
IEnumerator<T> IEnumerable<T>.GetEnumerator() { /* ... */ }
// IEnumerable explicit interface implementation
IEnumerator IEnumerable.GetEnumerator() { /* ... */ }

在实现泛型IEnumerable接口时,还必须实现非泛型IEnumerable接口。该错误是关于缺少非泛型方法。

IEnumerable的声明如下:

public interface IEnumerable<out T> : IEnumerable
{
    new IEnumerator<T> GetEnumerator();
}

注意新的关键字。

下面是IEnumerable的声明:
public interface IEnumerable
{
    IEnumerator GetEnumerator();
}

现在你有了一个GetEnumerator方法,但你实现的是这两个中的哪一个?因此,您需要添加非泛型版本的显式实现:

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