What code creates the captured variables / closures?

I understand that variable capture is done by the compiler, not by classes in the .NET platform itself. However, when DLR was introduced, part of this work certainly had to be done as part of the framework in order to defer it to execution time.

For example, in the code snippet below:

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

Resolution of the type of the variable d and its verification that it is an integer must be performed at run time. And since d is a variable in the lambda containing method, it will be locked. This part will certainly be executed at runtime.

Therefore, I believe that in this part there should be a part of the DLR assembly ( System.Core.dll ) that performs this role.

I searched, and I could find some classes that look suspiciously reprehensible for this kind of task. In particular, ExpressionQuoter (despite the appearance of this class, this class does not quote lambda expressions like the Expression.Quote method), HoistedLocals , but VariableBinder .

I thought I would invite someone who knows best what to say.

Which class or part of the .NET environment converts locators that contain lambdas methods (or anonymous methods) to those individual classes that have static variables that represent them?

+6
source share
2 answers

And since d is a variable in the containing lambda method, it will be captured in closure.

d does not need to be captured because lambda does not use it. If the C # compiler decides to capture it (which is not forbidden in accordance with the as-if rule), it will not be available in any way.

I believe that func(d) is executed like any method call with a dynamic argument.

Let's look at:

 dynamic d = ...; //maybe "1" Func<bool> func = (() => d == "1234"); 

I think this is more in the spirit of what you want to know (Update: indeed, you just edited the question to have this template). Now lambda depends on d , which was not there before.

Here d is fixed in the generated closure class as a field of type object . dynamic always compiled as object (possibly with a user attribute with it). Then the body of the lambda code proceeds to use standard dynamic operations.

Since all variable references in C # are statically bound to a specific variable, you never need to capture a dynamic number of fields or anything like that. Capture fields are statically known.

0
source

Which class or part of the .NET environment converts locales that are in containing lambda methods (or anonymous methods) into those separate classes that are static variables?

No, this is a compiler that does the job.

How would the values ​​of variables be passed to an individual method? The only way to do this is to define a new helper class, which also defines a field for each value that you want to pass back code. In addition, the callback code must be defined as an instance method in this helper class. Then Using LocalVariablesInTheCallbackCodemethod would be to build an instance of the helper class, initialize the fields from the values ​​into its local variables, and then build the delegate object associated with the helper object / instance method.

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

From the book CLR Via C #

With your code, a class is created that looks like this:

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

and your code compiled into something like:

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

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

When the lambda expression forces the compiler to generate a class with parameter / local variables converted to fields, the lifetime of the objects to which the variables belong is lengthened. Typically, a Parameter / local variable is outside the scope of the last use of the variable inside the method. However, the transformation of a variable into a field leads to the fact that the field saves the object, which it refers to the whole lifetime of the object containing the field . This is not great in most applications, but it is what you need to be aware of.

+2
source

All Articles