使用密钥优化Linq

时间:2012-12-05 19:01:36

标签: c# linq c#-4.0 linq-to-objects

基础知识:

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到对象。

2 个答案:

答案 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 无法执行此操作的原因。