Dan*_*Tao 10 .net c# linq delegates predicate
注意:在发布这个问题之前,我发现有一个更好的方法来做我想要完成的事情(我觉得它很愚蠢):
IEnumerable<string> checkedItems = ProductTypesList.CheckedItems.Cast<string>();
filter = p => checkedItems.Contains(p.ProductType);
Run Code Online (Sandbox Code Playgroud)
好的,是的,我已经意识到这一点.但是,无论如何,我发布了这个问题,因为我仍然不明白为什么我(愚蠢地)试图做的事情不起作用.
我觉得这很容易.原来它让我很头疼.
基本思路:显示ProductType在a中检查其属性值的所有项目CheckedListBox.
实施:
private Func<Product, bool> GetProductTypeFilter() {
// if nothing is checked, display nothing
Func<Product, bool> filter = p => false;
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == pt);
}
return filter;
}
Run Code Online (Sandbox Code Playgroud)
但是,如果在ProductTypesList(a CheckedListBox)中检查了"权益"和"ETF"项目.然后由于某种原因,以下代码仅返回"ETF"类型的产品:
var filter = GetProductTypeFilter();
IEnumerable<Product> filteredProducts = allProducts.Where(filter);
Run Code Online (Sandbox Code Playgroud)
我猜想它可能与一些自我引用的混乱有关filter,其本质上是本身或其他东西.而且我认为可能会使用......
filter = new Func<Product, bool>(p => (prevFilter(p) || p.ProductType == pt));
Run Code Online (Sandbox Code Playgroud)
......会做的,但没有这样的运气.任何人都能看到我在这里失踪的东西吗?
我相信你在这里有一个修改过的闭包问题.该pt参数绑定到lambda表达式,但随着循环的进行而更改.重要的是要意识到在lambda中引用变量的时候它是捕获的变量,而不是变量的值.
在循环中,这具有非常显着的分支 - 因为循环变量正在改变,而不是重新定义.通过在循环内创建变量,您将为每次迭代创建一个新变量 - 然后使lambda独立地捕获每个变量.
期望的实施将是:
foreach (string pt in ProductTypesList.CheckedItems.Cast<string>()) {
string ptCheck = pt;
Func<Product, bool> prevFilter = filter;
filter = p => (prevFilter(p) || p.ProductType == ptCheck);
}
Run Code Online (Sandbox Code Playgroud)
Eric Lippert撰写了有关此特定情况的文章:
另外,请参阅访问修改闭包(2)的问题,以便更好地解释闭包变量会发生什么.博客The Old New Thing上还有一系列文章,对此有一个有趣的观点: