代码检查:访问已释放的捕获变量
首先,让我们确保您理解什么是 闭包。 简单来说,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); };
在上面的示例中, print 将捕获变量 myStr (而不是其 值 ),并且仅在您调用 print() 时获取 myStr 的 值。
在更复杂的场景中,当闭包定义在一个变化的上下文中时,它可能不会按预期运行。
可能发生这种情况的情形之一是闭包定义在 using 语句内部:
void Foo(string fileName, string text)
{
using (var writer = new StreamWriter(fileName))
{
ExecuteDelayed(() => { writer.Write(text); });
}
}
private static void ExecuteDelayed(Action action)
{
// execute action
}
在上述代码中,ReSharper 会针对 writer.Write(text); 发出 访问已释放的闭包警告。 原因是 ExecuteDelayed() 可能会在 writer 的作用域被释放后执行 lambda,这将导致运行时异常。
如果 ExecuteDelayed() 在堆栈上完成了对 lambda 的处理,您可以使用 InstantHandle属性标记 action 参数:
private static void ExecuteDelayed([InstantHandle]Action action)
{
// execute action
}
这将告诉 ReSharper 的代码分析引擎,在这种上下文中使用 ExecuteDelayed() 是安全的,不会发出任何警告。
最后修改日期: 2025年 9月 27日