Code inspection: Access to disposed captured variable
Category: Potential Code Quality Issues
ID: AccessToDisposedClosure
EditorConfig: resharper_access_to_disposed_closure_highlighting=[error|warning|suggestion|hint|none]
Language: C#, VB.NET
Requires SWA: No
tip
First of all, let's make sure that you understand what a closure is. To put it simply, a closure in C# is a lambda expression or an anonymous method that captures some variables from an outer scope. Here is the simplest example:
// 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); };
In the example above, print
will capture the variable myStr
(and not its value) and will only get the value of myStr
when you invoke print()
.
In more complex scenarios, when a closure is defined in a changing context, it may not behave as expected.
One of the situations where it may happen is a closure defined inside a using
statement:
void Foo(string fileName, string text)
{
using (var writer = new StreamWriter(fileName))
{
ExecuteDelayed(() => { writer.Write(text); });
}
}
private static void ExecuteDelayed(Action action)
{
// execute action
}
In the above code, ReSharper issues the Access to disposed closure warning for writer.Write(text);
. The reason for that is ExecuteDelayed()
could execute the lambda after the writer
's scope is disposed, which will result in a runtime exception.
If the ExecuteDelayed()
completes processing of the lambda on the stack, you can mark the action
parameter with the InstantHandle attribute:
private static void ExecuteDelayed([InstantHandle]Action action)
{
// execute action
}
This will tell ReSharper's code analysis engine that using ExecuteDelayed()
is safe in such contexts, and no warnings will be issued.