When are closure properties evaluated?

Several methods in our code base use MaybeObject, which can be passed to functions when the result can be known, or can rely on an external call to a web service that has not yet been executed. For example, the property below can either have the specified known value, or not specify and call after the asynchronous call is completed, it will return the result of the Async call.

private string _internalString; public string stringProp { get { if (!string.IsNullOrEmpty(_internalString)) return _internalString; return resultOfAsyncCallFromSomewhereElse; } set { _internalString = value; } } 

Obviously, trying to reference a property before ending the asynchronous call will result in the null reference being thrown out, so we also have a flag to check if this value is available.

The question is, in the code below, would it be creating a lambda attempt and evaluating stringProp (which has not yet been filled), or will the evaluation be postponed until the resulting action is called (which will complete the asynchronous operation after verification)?

 public Action ExampleMethod(MaybeObject maybe) { return () => doSomethingWithString(maybe.stringProp); } 
+7
source share
6 answers

Evaluation will be deferred until the resulting action is called.

The code referenced by the delegate is executed only when the delegate itself is called directly, regardless of how the delegate itself was created .

For example, these methods of passing code to execute through the Action delegate are equivalent, and the doSomethingWithString method doSomethingWithString n’t execute before calling Action() :

Explicit Method (.NET 1.1):

 private MaybeObject maybe; public Action ExampleMethod() { return new Action(DoSomethingWithMaybeObject); } private void DoSomethingWithMaybeObject() { doSomethingWithString(maybe.stringProp) } 

Anonymous Method (.NET 2.0):

 public Action ExampleMethod(MaybeObject maybe) { return delegate() { doSomethingWithString(maybe.stringProp) }; } 

Lambda (.NET 3.5):

 public Action ExampleMethod(MaybeObject maybe) { return () => doSomethingWithString(maybe.stringProp); } 

See also:

+3
source

In C #, everything will be evaluated at runtime, since C # lambda Closures is not a true closure that can resolve the state of a captured environment at the time of creation.

 () => doSomethingWithString(maybe.stringProp); 

Here even the maybe link can be null and you won’t get any problems, such as NullReferenceException, until the delegate is executed. This trick is sometimes used to resolve late values.

Wikipedia: Closing :

Closing saves a reference to the environment at the time it was created (for example, to the current value of a local variable in the enclosing area), while a general anonymous function does not need this.

Good overview of C # Clocure features - Anonymous methods and closures in C #

From the definition of closure, we can conclude that Closure remembers the values ​​of variables during its creation. However, in C #, an external local variable (in this case) is used in conjunction with an anonymous method, creating it on the heap. This means that any change in the anonymous method changes the original value, and when the method is called the second, when it receives the changed value I as 1 (see the second line of output). This leads many to argue that the anonymous method is not really a closure, because by its definition, the value of a variable at the time of creating Closure should be remembered and not amenable to change.

+5
source

Properties in the closure are not evaluated until the action is launched, because the properties are methods, not values. Accessing MyObject.MyProperty is like calling the code MyObject.get_MyProperty (), so you can get different behavior when using a property and using a base variable.

+2
source
 In .net closures are passed as reference so they are executed as they are evaluated, the same reason you can do something like this. EventHandler handler = null; handler = (sender, args) => { // event handler do something}; SomeEvent += handler; 
0
source

it would be a hyphen. ExampleMethod () returns a delegate of the anonymous function () => doSomethingWithString (maybe.stringProp), so doSomethingWithString () will not be called until this delegate is called

0
source

You have to try it yourself to see what happens!

In this case, it seems that the closure is really around MaybeObject , and not just the string property (since the object is passed to Action). The string property is not available until the action is completed.

But even if the string itself was a variable set to close ...

 string s = ""; Func<bool> isGood = () => s == "Good"; s = "Good"; Console.WriteLine(isGood()); // prints 'True' 

Here you can see that the closure is performed around the line, but it is not evaluated before execution.

Delegates work just like any other function - they actually do nothing until they are called.

0
source

All Articles