2008-10-10 52 views
11

假设我的对象处于完美工作状态(即TDD让我认为它们工作正常)。以编程方式构建LINQ查询,而无需本地变量欺骗我

我有这样创建(除缩进正确)的列表:

var result = from v in vendors 
      from p in v.Products 
      orderby p.Name 
      select p; 

这工作 - 我得到的所有产品全部供应商。

现在我有一个条件列表,由用户在运行时建立。让我们来运用它们:

foreach (Attribute a in requiredAttributes) 
{ 
    result = result.Where(p => p.Attributes.Contains(a)); 
} 

这可能是原始的,但我认为它会起作用。但是,在这个foreach循环完成后,当枚举“result”时,它将包含所有在其Attributes属性(也是集合)中具有requiredAttributes集合的LAST属性的产品。

对我来说,这个味道像“a”被每个行程通过循环覆盖,只有最后一个适用。

不知何故向IEnumerable写了一个名为ContainsAll(IEnumerable)的扩展方法,或者是那种效果,我该如何实现我想要的,这基本上是一个逻辑AND,只给出那些具有所有必需属性的产品?

+0

感谢家伙 - 我给予Jon的“接受答案”,因为它似乎可能更适合“一般”情况。但我肯定会检查出奥默的建议,不知道你能做到这一点。投票给所有人。 :) – 2008-10-10 06:30:56

+0

解决此问题的新方法是仅使用C#5。另见[在foreach中使用变量在C#5中进行了更改?](http://stackoverflow.com/a/12112959/18192) – Brian 2016-01-15 14:38:38

回答

19

(编辑为清楚起见。)

问题是foreach循环,并且“一个”可变正被捕获,然后将实际上每次改变。这里有一个修改,它将有效地为循环的每次迭代引入一个“新”变量,并捕获该新变量。

foreach (Attribute a in requiredAttributes) 
{ 
    Attribute copy = a; 
    result = result.Where(p => p.Attributes.Contains(copy)); 
} 

奥马尔的解决方案是一种清洁的,如果你可以使用它,但是这可能会帮助,如果你真正的代码实际上是更复杂的:)

编辑:有更多的问题this closures article - 向下滚动到“比较捕捉策略:复杂性与权力”。

7
var result = from v in vendors 
      from p in v.Products 
      where requiredAttributes.All(a => p.Attributes.Contains(a)) 
      orderby p.Name 
      select p; 

HTH。

5

我没有编写它,但改变

foreach (Attribute a in requiredAttributes){  
    result = result.Where(p => p.Attributes.Contains(a)); 
} 

foreach (Attribute a in requiredAttributes){  
    Attribute b = a; 
    result = result.Where(p => p.Attributes.Contains(b)); 
} 

应该修复它太,我认为。