Closing. The difference between capturing variables and reading them as arguments.

Say we have this class:

// Provides deferred behaviour public class Command<TResult> { private Func<object[], TResult> _executeFunction; private object[] _args; public Command(Func<object[], TResult> execution, params object[] arguments) { _executeFunction = execution; _args = arguments; } public TResult Execute() { return _executeFunction(_args); } } 

What is the difference between these two anonymous functions?

 int a = 1; int b = 4; // a and b are passed in as arguments to the function Command<int> sum = new Command<int>(args => (int)args[0] + (int)args[1], a, b); // a and b are captured by the function Command<int> sum2 = new Command<int>(_ => a + b); Console.WriteLine(sum.Execute()); //Prints out 5 Console.WriteLine(sum2.Execute()); //Prints out 5 

I am specifically looking for performance differences.

In addition, we know that if any class contains a link sum2 , then a and b will go beyond the scope in which they were defined, probably will never be collected by GC if the function is still referenced somewhere.

Does the same thing happen with sum ? (Given that the arguments are reference types, not value types, as in this example)

+5
source share
1 answer

When you pass variables a and b , you are doing just that. Values 1 and 4 are transmitted respectively. However, when you refer to a and b in the context (or scope) of a lambda expression, the values ​​are "captured." Variables a and b , within the framework of the lambda expression, are considered as references to the originals out of scope, which means that if they are changed within the lambda, they are the same as the originals. When compiled to IL, they are in the class where the instances are shared.

 static void Main() { int a = 1; int b = 4; // a and b are passed in as arguments to the function var sum = new Command<int>(args => (int)args[0] + (int)args[1], a, b); // a and b are captured by the function var sum2 = new Command<int>(_ => { var c = a + b; a++; b++; return c; }); Console.WriteLine(sum.Execute()); //Prints out 5 Console.WriteLine(sum2.Execute()); //Prints out 5 Console.WriteLine("a = " + a); // Prints 2 Console.WriteLine("b = " + b); // Prints 5 Console.ReadLine(); } 

There are really few differences in IL, and I do not believe that there are any performance implications that one or the other should avoid. I usually prefer to use lambda expressions for their readability.

Look at some of the ILs generated from some C # lambdas .

+1
source

Source: https://habr.com/ru/post/1238182/


All Articles