JetBrains Rider 2025.2 Help

代码检查:在闭包中访问 foreach 变量

首先,让我们确保您理解什么是 闭包。 简单来说,C# 中的闭包是一个 lambda 表达式或匿名方法,它捕获了外部作用域中的一些变量。 以下是最简单的示例:

// A self-contained lambda. Not a closure. Action printOne = () => { Console.WriteLine("one"); }; // A closure – a lambda that captures a variable from an outer scope. string myStr = "one"; Action print = () => { Console.WriteLine(myStr); };

在上述示例中, 打印 将捕获变量 myStr (而不是其 ),并且仅在您调用 打印() 时获取 myStr

在更复杂的场景中,当闭包定义在一个变化的上下文中时,它可能不会按预期运行。

这种情况可能发生在闭包定义在 foreach 语句中,并使用 C# 4.0(Visual Studio 2010)或更早版本编译时。

在 C# 5.0(Visual Studio 2012)之前,编译器会将 foreach 展开为 当...时 语句,并将迭代变量定义在循环外部。 因此,如果此变量在闭包中使用,稍后调用此闭包时总是会获取到循环最后一次迭代对应的值:

var myActions = new List<Action>(); var myStrings = new List<string>() { "one", "two", "three" }; foreach (var str in myStrings) { myActions.Add(() => { Console.WriteLine(str); }); } myActions[0](); // "three" is printed

JetBrains Rider 检测到此问题,并建议通过将循环变量的值复制到定义闭包的作用域中来修复它:

var myActions = new List<Action>(); var myStrings = new List<string>() { "one", "two", "three" }; foreach (var str in myStrings) { var str1 = str; myActions.Add(() => { Console.WriteLine(str1); }); } myActions[0](); // "one" is printed

此修复确保当您从 myActions 中选择一个操作并获取创建此操作的上下文时, str 将持有相应迭代的值。

最后修改日期: 2025年 9月 26日