我在这个谓词链中缺少什么?
注意:在发布这个问题之前,我突然想到有一种更好的方法可以完成我想要完成的任务(我觉得这很愚蠢):
IEnumerable<string> checkedItems = ProductTypesList.CheckedItems.Cast<string>();
filter = p => checkedItems.Contains(p.ProductType);
所以好吧,是的,我已经意识到了这一点。然而,我还是发布了这个问题,因为我仍然不太明白为什么我(愚蠢地)尝试所做的事情不起作用。
我认为这会非常容易。事实证明这让我很头疼。
基本思想:在 CheckedListBox
中显示其 ProductType
属性值被选中的所有项目。
实现:
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;
}
但是,假设项目“Equity”和“ETF”都在 ProductTypesList
(CheckedListBox
)中检查。然后由于某种原因,以下代码仅返回“ETF”类型的产品:
var filter = GetProductTypeFilter();
IEnumerable<Product> filteredProducts = allProducts.Where(filter);
我猜它可能与一些自引用混乱有关,其中 filter
本质上设置为自身 或者其他东西。我想也许使用……
filter = new Func<Product, bool>(p => (prevFilter(p) || p.ProductType == pt));
可以解决问题,但没有这样的运气。有人能看到我在这里缺少什么吗?
NOTE: Right before posting this question it occurred to me there's a better way of doing what I was trying to accomplish (and I feel pretty stupid about it):
IEnumerable<string> checkedItems = ProductTypesList.CheckedItems.Cast<string>();
filter = p => checkedItems.Contains(p.ProductType);
So OK, yes, I already realize this. However, I'm posting the question anyway, because I still don't quite get why what I was (stupidly) trying to do wasn't working.
I thought this would be extremely easy. Turns out it is giving me quite a headache.
The basic idea: display all the items whose ProductType
property value is checked in a CheckedListBox
.
The implementation:
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;
}
However, say the items "Equity" and "ETF" are both checked in ProductTypesList
(a CheckedListBox
). Then for some reason, the following code only returns products of type "ETF":
var filter = GetProductTypeFilter();
IEnumerable<Product> filteredProducts = allProducts.Where(filter);
I guessed it might have had something to do with some self-referencing messiness where filter
is set to, essentially, itself or something else. And I thought that maybe using ...
filter = new Func<Product, bool>(p => (prevFilter(p) || p.ProductType == pt));
...would do the trick, but no such luck. Can anybody see what I am missing here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我相信您在这里遇到了修改后的闭包问题。
pt
参数绑定到 lambda 表达式中,但随着循环的进行而发生变化。重要的是要认识到,当在 lambda 中引用变量时,捕获的是变量,而不是变量的值。在循环中,这有一个非常重要的后果 - 因为循环变量正在改变,而不是被重新定义。通过在循环内创建变量,您可以为每次迭代创建一个新变量,然后允许 lambda 独立捕获每个变量。
所需的实现是:
Eric Lippert 已写过有关此具体情况的文章:
另外,请参阅问题访问修改后的闭包(2),很好地解释了闭包变量会发生什么。博客 The Old New Thing 上还有一系列文章对此提出了有趣的观点:
I believe you have a modified closure problem here. The
pt
parameter is bound into the lambda expression but changes as the loop progresses. It's important to realize the when a variable is referenced in a lambda it is the variable that is captured, not the value of the variable.In loops this has a very significant ramification - because the loop variable is changing, not being redefined. By creating a variable inside the loop, you are creating a new variable for each iteration - which then alows the lambda to capture each independently.
The desired implementation would be:
Eric Lippert has written about this specific situation:
Also, see the question Access to Modified Closure (2) for a good explanation of what happens with closure variables. There's also an series of articles on the blog The Old New Thing that has an interesting perspective on this:
这与闭包有关。变量 pt 将始终引用 for 循环的最后一个值。
考虑以下示例,其中输出是预期的,因为它使用作用域位于 for 循环内的变量。
It has to do with closures. The variable pt will always refer to the last value of the for loop.
Consider the following example where the output is the one expected because it's using a variable that is scoped inside the for loop.
由于您正在循环并将过滤器类型设置为自身,因此您在每种情况下都将产品类型设置为最后一个
pt
。它是一个经过修改的闭包,并且由于它是延迟绑定的,因此您需要在每个循环上复制它,如下所示:这应该会产生正确的结果,否则最后一个 pt 用于所有相等检查。
Since you're looping and setting the filter type to itself, you're setting the product type to the last
pt
in each case. It's a modified closure and since it's delay bound, you need to copy it on each loop, like this:This should result in the right result, otherwise the last
pt
is used for all equality checks.