Lambda表达式中的闭包修改访问

4
foreach(var category in categories) {
    a.AddRange(_db.Articles.Where(c => c.Categories.Contains(category)));
}

代码可以正常运行,但是我收到了一个关于"访问已修改的闭包"的警告,这是针对在lambda表达式中使用的category的。
问题:在这种情况下,这个警告是否有任何影响?

请参考这个相关问题:https://dev59.com/Vmox5IYBdhLWcg3w6oZf。它可能也会有所帮助。 - J. Holmes
1
嗯,在SO上有十几个与“访问修改的闭包”相关的结果,其中任何一个都可以回答这个问题。 - Raymond Chen
@RaymondChen 有一些答案,但它们没有解决 lambda 上下文是我提问的唯一原因。我理解闭包的概念,只是想看看在这种奇怪的情况下,它是否在 LINQ 的上下文中意味着更具体的东西。 - one.beat.consumer
C# 5 更改了此行为,使类别变量具有当前迭代中的值而不是最后一个值。iomagazine.com/Articles/2012/11/01/More-Than-Just-Async.aspx?Page=1 - Marcos Meli
2个回答

6
这里的警告是因为您在Where lambda的闭包内访问变量category。每次迭代时,category的值都会更改,Where延迟执行,因此它将看到当前category的值,而不是lambda创建时的值。
在这种情况下,您可能没问题。即使Where被延迟执行,AddRange方法也很快,并且将强制评估Where以完成。因此,Where方法将看到它期望的category的值。
如果您想消除警告,请简单地声明一个迭代变量的本地副本,并捕获该副本。
foreach(var category in categories) {
  var localCategory = category;
  a.AddRange(_db.Articles.Where(c => c.Categories.Contains(localCategory)));
}

我认为这是我忘记了关于foreach循环的某些内容 - 迭代变量category在技术上是在循环外面,就像这个伪代码int i; for (i <= 10) { i++; }?如果是这样的话,我理解 - Where可能会在category更改后进行评估?我的理解正确吗? - one.beat.consumer

0

它告诉你“category”变量存在于闭包中,可以在LINQ表达式之外进行修改。

查看这里的问题以获取一些解释。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接