Let's 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's 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'm specifically looking for performance differences.
Also, we know that if some class is holding a reference of sum2, then a and b will live beyond the scope they were defined on, probably never getting collected by the GC if the function is still referenced anywhere.
Does the same happen with sum? (Considering the arguments are reference types and not value types as in this example)
When you pass in the variables a and b, you are doing just that. The value of 1 and 4 are passed in respectively. However, when you refer to a and b within the context (or scope) of the lambda expression the values are "captured". The variables a and b, within the scope of the lambda expression are treated as references to the originals outside of the scope, meaning that if they are changed within the scope of the lambda -- so too are the originals. When compiled into IL, they reside in a 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 is really small difference in the IL, and I do not believe there is any performance implications worth avoiding one or the other. I would usually prefer the usage of lambda expressions for their readability.
A look at some of the IL generated from some C# lambdas.
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