Short answer: no. .NET doesn't need to walk up the scope chain to find the variables.
Long answer:
Start with this example:
static Func<string> CaptureArgs(int a, int b)
{
return () => String.Format("a = {0}, b = {1}", a, b);
}
static void Main(string[] args)
{
Func<string> f = CaptureArgs(5, 10);
Console.WriteLine("f(): {0}", f());
// prints f(): a = 5, b = 10
}
In the CaptureArgs
method, a
and b
exist on the stack. Intuitively, if we reference the variables in an anonymous function, return the function and popping the stack frame should remove a
and b
from memory. (This is called the upward funargs problem).
C# doesn't suffer from the upwards funargs problem because, behind the scenes, an anonymous function is just fancy syntax sugar over a compiler-generated class. The C# code above turns into:
private sealed class <>c__DisplayClass1
{
// Fields
public int a;
public int b;
// Methods
public string <CaptureArgs>b__0()
{
return string.Format("a = {0}, b = {1}", this.a, this.b);
}
}
The compiler creates and returns a new instance of <>c__DisplayClass1
, initializes its a
and b
fields from the a
and b
passed into the CaptureArgs
method (this effectively copies a
and b
from the stack to fields existing on the heap), and returns it to the caller. Calling f()
is really a call to <>c__DisplayClass1.<CaptureArgs>b__0()
.
Since the a
and b
referenced in <CaptureArgs>b__0
are vanilla fields, they can be referenced directly by the delegate, they don't require any special sort of scope chaining rules.