将LINQ转换为普通Foreach
本文关键字:Foreach LINQ 转换 | 更新日期: 2023-09-27 18:27:19
我在我们的一个项目中发现了下面的一段代码。我被困了两天:-(试图理解Aggregate和LinQKit Expand.
你能帮助将LINQ以下转换为正常的前臂操作吗?
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());
函数在项集合上迭代,并通过为每个ClientId
属性值添加or
条件来构建谓词。
在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
)非常大时,就会变得不可读,而且最重要的是,您无法先验地知道硬编码它们的值是什么。因此,为了克服这个问题,解决方案是用一组可变的值来概括上面的谓词。这只需使用以下算法即可完成:
- 创建一个返回
false
的Expression
;如果我们返回true
,编译器将缩短评估(因为我们使用的是or
),并将为所有项返回true - 对于值集合中的每个项,添加一个具有该项值的
or
子句
现在,您的示例可以通过以下方式转换为foreach:
// start with a predicate returning false
// this is the seed of the Aggregate method
Expression<Func<Purchase, bool>> predicate = m => false;
// Now, iterate the collection and build the full predicate
foreach( var id in idList)
{
// Build the predicate by invoking a function which returns the client id of the
// purchase and comparing it with the value of the current id from the idList
predicate = predicate.Or(item => item.ClientId == id);
}
希望这能有所帮助。