2

基础知识:

IDictionary<TKey, TValue>延伸IEnumerable<T>

public interface IDictionary<TKey, TValue>: .., 
    IEnumerable<KeyValuePair<TKey, TValue>>
{
  ... 
} 

该类Enumerable提供了扩展方法,这些方法提供了whereLINQ 中子句的实现

 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.

如果Listimplements 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>和表达式树做同样的事情,但我的问题是关于 LINQ-to-Objects。

4

2 回答 2

0

不,你没有错过任何东西。LINQ知道的唯一键控集合是Lookup<TKey, TElement>class,即便如此,它也没有做任何特别的事情,它只是归结为Lookup<TKey, TElement>implements IEnumerable<IGrouping<TKey, TElement>>; 所以实际上,您正在迭代IGrouping<TKey, TElement>接口实现。

IEnumerable<T>也就是说,LINQ 对接口之外的接口没有任何特殊知识;恰好IDictionary<TKey, TValue>接口扩展了IEnumerable<KeyValuePair<TKey, TValue>>,这就是为什么您可以首先对其执行操作的原因。

但是,对于具有特定查找机制的任何类型,您需要嗅探类型(在 LINQ 中经常这样做),然后在可能的情况下调用特定于类型的操作。如果类型嗅探失败,您可以求助于与IEnumerable<T>.

就像你在这里做的一样。

于 2012-12-05T19:11:16.690 回答
0

您可以Where在字典上实现自定义以分析传入的表达式,如果它看起来像键控访问,请使用特殊的字典工具。

在我看来,这只是一个理论上的选择。不应该这样做。相反,应该调整过滤机制,以便它以正确的方式使用字典。

另请注意,一旦您将不透明的代码传递Func<T, bool>给其他代码,这段代码就无法查看您传入的委托内部。它无法注意到存在键控访问。所以这就是为什么 LINQ to Objects不能做到这一点。

于 2012-12-05T19:25:39.580 回答