LINQ在实现IEnumerable<;T>;两次

本文关键字:gt 两次 lt IEnumerable LINQ 实现 | 更新日期: 2023-09-27 17:59:38

我的类实现了两次IEnumerable<T>如果不每次都铸造hashtable,如何让LINQ工作


我编写了自己的协变哈希表实现,它也继承自。NET的CCD_ 3。最终,它为T实现了两次不同类型的IEnumerable<T>。我隐式地实现了主可枚举接口,另一个显式地实现。类似这样的东西(伪代码):

class HashTable<TKey, TValue> :
    ...
    IEnumerable<out IAssociation<out TKey, out TValue>>,
    IEnumerable<out KeyValuePair<TKey, TValue>>
{
    // Primary:
    public IEnumerator<IAssociation<TKey, TValue>> GetEnumerator();
    // Secondary:
    IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator();
}

当我foreach哈希表时,它会像预期的那样使用主可枚举值:

using System;
using System.Collections.Generic;
using System.Linq;
var hashtable = new HashTable<string, int>();
foreach (var kv in hashtable)
{
    // kv is IAssociation<string, int>
}

现在我希望它在LINQ中做同样的事情,但它会向我抛出编译器错误,因为它不知道为扩展方法选择哪个接口:

var xs1 = from x in hashtable          // <-- 1
          select x;
var xs2 = hashtable.Select(x => x);    // <-- 2

错误1:找不到源类型"HashTable"的查询模式的实现选择"未找到"。请考虑显式指定范围变量"x"的类型。

错误2:"HashTable"不包含"Select"的定义,并且找不到接受"HashTable"类型的第一个参数的扩展方法"Select"(是否缺少using指令或程序集引用?)

也许有一些接口或继承技巧我不知道?


对于那些询问的人来说,以下是完整的接口树:

using SCG = System.Collections.Generic;
public class HashTable<TKey, TValue>
    : IKeyedCollection<TKey, TValue>, SCG.IDictionary<TKey, TValue>
public interface IKeyedCollection<out TKey, out TValue>
    : ICollection<IAssociation<TKey, TValue>>
public interface ICollection<out T> : SCG.IEnumerable<T>
public interface IAssociation<out TKey, out TValue>
// .NET Framework:
public interface IDictionary<TKey, TValue>
    : ICollection<KeyValuePair<TKey, TValue>>
public interface ICollection<T>
    : IEnumerable<T>

现在你可以理解为什么我不能使KeyValuePair<TKey, TValue>IAssociation<TKey, TValue>相同了。

LINQ在实现IEnumerable<;T>;两次

在使用表达式作为方法调用的参数时,必须理解编译器没有"主要"answers"次要"接口实现的概念。就转换到IEnumerable<IAssociation<...>>IEnumerable<KeyValuePair<...>>这两种类型而言,您的类型实现得同样好。这就是编译器需要更多信息的原因。

最简单的方法(IMO)是引入两种新特性:

public IEnumerable<IAssociation<TKey, TValue>> Associations { get { return this; } }
public IEnumerable<KeyValuePair<TKey, TValue>> KeyValuePairs { get { return this; } }

这意味着你可以很容易地具体化:

var query = from x in table.Associations
            ...;

var query = from x in table.KeyValuePairs
            ...;

这不仅有助于让编译器满意,也有助于任何试图读取代码的人。如果发现其中一个比另一个使用得更多,则可以始终使HashTable只实现一个IEumerable<>,并键入并保留另一个属性。