将LINQ转换为普通的Foreach

时间:2014-10-21 03:51:37

标签: c# linq linqkit

我在下面的一个项目中找到了一段代码。 我被困了两天:-(试图了解Aggregate& LinQKit展开。

你能帮助将LINQ转换为正常的foreach操作吗?

public Expression<Func<Purchase, bool>> forTarget(List<string> idList)
{
    Expression<Func<Purchase, string>> fc = p => p.ClientId;
    Expression<Func<Purchase, bool>> predicate = m => false;

    return idList.Aggregate(predicate, (p, id) => p.Or(m => fc.Invoke(m) == id), p => p.Expand());
}

internal class Purchase
{
    public int Price { get; set; }
    public string Description { get; set; }
    public string ClientId { get; set; }
}

public class Client
{
    public string Id { get; set; }
}   

或者至少,任何关于这个LINQ表达式在列表上做什么的指针都会非常有帮助。

return idList.Aggregate(predicate,
        (p, id) => p.Or(m => fc.Invoke(m) == id),
        p => p.Expand());

1 个答案:

答案 0 :(得分:2)

该函数迭代一组项,并通过为每个or属性值添加ClientId条件来构建谓词。

在Linq2SQL的早期版本中,不支持方法Contains,因此您无法执行这样的查询:

IEnumerable<Purchase> purchases = LoadSelectedItems();
var clientIds = purchases.Select( p => p.ClientId ).ToArray();
var results = db.Clients.Where( c => clientIds.Contains( c.Id )); // Did not work.

此问题的解决方法是创建一个谓词,该谓词将使用or检查Id是否与特定值匹配。因此,对于上面的示例,如果clientIds = {1, 2, 3} Where子句将被写为:

var results = db.Clients.Where( c => c.Id == 1 || c.Id == 2 || c.Id == 3);

正如你所看到的,这种陈述不是很优雅,当要检查的值集合(即clientIds)非常大时变得不可读,而且最重要的是,你无法知道先验是什么值将是硬编码。 因此,为了克服这个问题,解决方案是使用可变的值集合来推广上述谓词。这只需使用以下算法即可完成:

  1. 创建一个返回Expression的{​​{1}};如果我们返回false,编译器将使评估短路(因为我们正在使用true)并且将为所有项返回true;
  2. 对于值集合中的每个项目,添加or子句以及项目的值。
  3. 现在,您的示例可以通过以下方式转换为foreach:

    or

    希望这有帮助。