我的班级实施了IEnumerable<T>
两次。 如何在不每次投射hashtable
的情况下让LINQ工作?
我编写了自己的协变哈希表实现,它也继承自.NET的IDictionary<TKey, TValue>
。最终,它为IEnumerable<T>
实现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
哈希表时,主要可枚举需要as expected:
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'的定义,也没有扩展方法'Select'接受类型为'HashTable'的第一个参数'(你是否缺少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>
相同。
答案 0 :(得分:25)
重要的是要理解,当使用表达式作为方法调用的参数时,编译器没有“主要”和“次要”接口实现的概念。对于这些类型的转换,您的类型同样可以同时实现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<>
并键入并保留其他属性。