Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which is the code that creates captured variables / closures?

I understand that variable capturing is done by the compiler and not by the classes in the .NET framework itself. However, when the DLR was introduced, some of this work must surely have needed to have been done within the framework so as to defer it to runtime.

For e.g., in the piece of code given below:

dynamic d = ...

Func<int, bool> func = n => n > d;

The type resolution of the variable d and its verification that it is an integer must have to be done at run-time. And since d is a variable in the containing method of the lambda, it will be captured into a closure. This part will surely be done at run time.

Hence, I infer there must be some part of the DLR assemblies (System.Core.dll mostly) that does this part.

I've been searching and I could find some classes that look suspiciously reprehensible for this sort of a task. Specifically, ExpressionQuoter (despite the looks of it, this class does not quote lambda expressions like the Expression.Quote method does), HoistedLocals, and the VariableBinder.

I thought I would invite someone who knows better to answer this.

Which class or part of the .NET framework turns locals that are in containing methods of lambdas (or anonymous methods) into those separate classes that have static variables representing them?

like image 694
Water Cooler v2 Avatar asked Jul 25 '15 11:07

Water Cooler v2


1 Answers

Which class or part of the .NET framework turns locals that are in containing methods of lambdas (or anonymous methods) into those separate classes that have static variables representing them?

No, it's the compiler that does the job.

How would the values of the variables be passed to the separate method? The only way to do this is to define a new helper class that also defines a field for each value that you want passed to the callback code. In addition, the callback code would have to be defined as an instance method in this helper class. Then, the UsingLocalVariablesInTheCallbackCodemethod would have to construct an instance of the helper class,initialize the fields fromthe values in its local variables, and then construct the delegate objectbound to the helper object/instance method.

This is very tedious and error-prone work, and, of course, the C# compiler does all this for you automatically

From the book CLR Via C#

With your code, there is a class generated that looks like:

class SomeClass
{
    public dynamic d;
    public bool yourCallBack(int n)
    {
        return n > d;
    }
}

and your code is compiled into something like:

dynamic d = ...
SomeClass class1= new SomeClass(); 
class1.d = d;
Func<int, bool> func = class1.yourCallBack;

There is also a note regarding the lifetime of captured variables:

When a lambda expression causes the compiler to generate a class with parameter/local variables turned into fields, the lifetime of the objects that the variables refer to are lengthened. Usually, a parameter/local variable goes out of scope at the last usage of the variable within a method. However, turning the variable into a field causes the field to keep the object that it refers to alive for the whole lifetime of the object containing the field. This is not a big deal in most applications, but it is something that you should be aware of.

like image 95
Khanh TO Avatar answered Sep 21 '22 01:09

Khanh TO