I've read that due to how the scope chain works in javascript, if we wish to refer to a variable V within a function F that is not declared within the F's scope, it is beneficial (yes in terms of performance) to declare a local variable V2 in F that references V, then accessing the object referenced by V through V2.
i'm wondering if this concept applies to the closures in C# and VB (accessing local variables in functions through lambdas)
Public Shared Function Example()
Dim a = 1
Dim b = New Object
Return Sub()
'when we use the variables a and b from here does it have to "go up the scope chain"
End Sub
End Function
btw i would prefer if the answer isn't premature optimization is the root of all evil
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With