基础知识:
IDictionary<TKey, TValue>
延伸IEnumerable<T>
public interface IDictionary<TKey, TValue>: ..,
IEnumerable<KeyValuePair<TKey, TValue>>
{
...
}
Enumerable
类提供了在LINQ中提供where
子句的实现的扩展方法
public static class Enumerable
{
...
public static IEnumerable<T> Where(this IEnumerable<T>,
bool Func<T> predicate)
{
...
}
}
使用LINQ时,编译器会将查询语法转换为Enumerable.Where
方法的调用。
当迭代从此方法返回的IEnumerable<T>
时,谓词将在集合项的每个上进行评估。
相应的项目会产生结果。
请求如下:
var l_res = from n in List where n.key == 1 select n;
将遍历List
中的每个项目。
如果List
实现IDictionary<TKey, TValue>
,并且where
子句在用作字典中的键的属性上,我如何利用该键来避免迭代每个记录和执行查找?
我已经知道我可以测试IEnumerable<T>
是否也是IDictionary<TKey, TValue>
实现,并选择哪个是最佳使用请求:
if(list is IDictionary<int, T>)
{
var l_res = ((IDictionary<int, T>) list)[1];
}
else
{
var l_res = from n in List where n.key == 1 select n ;
}
但我想知道我是否遗漏了LINQ中存在的处理类似关键字集合的内容。
注意:LINQ-to0SQL提供程序使用IQueryable<T>
和Expression树来做同样的事情,但我的问题是关于LINQ到对象。
答案 0 :(得分:0)
不,你没有遗漏任何东西。 LINQ知道的唯一键控集合是Lookup<TKey, TElement>
class,即使这样,它也没有做任何特殊的事情,它只是归结为Lookup<TKey, TElement>
实现{{1}的事实}};所以实际上,你正在迭代IGrouping<TKey, TElement>
interface实现。
也就是说,LINQ对IEnumerable<T>
interface以外的接口没有任何特殊的了解;恰好IDictionary<TKey, TValue>
interface扩展IEnumerable<IGrouping<TKey, TElement>>
,这就是为什么你可以首先对它进行操作。
但是,对于任何具有特定查找机制的类型,您需要嗅探类型(经常在LINQ中完成),然后在可能的地方调用特定于类型的操作。如果类型嗅探失败,您可以使用适用于IEnumerable<KeyValuePair<TKey, TValue>>
的实现。
就像你在这里一样。
答案 1 :(得分:0)
您可以在字典上实现自定义Where
,分析传入的表达式,如果它看起来像是键控访问,请使用特殊的字典工具。
在我看来,这只是一个理论选择。它不应该这样做。相反,应该调整过滤机制,使其以正确的方式使用字典。
另请注意,一旦将不透明Func<T, bool>
传递给其他代码,此另一段代码就无法查看您传入的代理内部。它无法注意到存在键控访问。这就是LINQ to Objects 无法执行此操作的原因。