Question

Lambda expressions are evaluated at compile time, so the below code will not generate a 100 different functions. Is there a simple mechanism to achieve the mentioned effect? I realize this isn't very efficient performance wise.

List<Action> actions = new List<Action>();
for (int i = 0; i < 100; ++i)
    actions.Add(() => Execute(100100100 + i));
Was it helpful?

Solution

This code closes over a modified variable, so it's not going to do what you want it to do. You need to add a temporary variable for the value of i, like this:

List<Action> actions = new List<Action>();
for (int i = 0; i < 100; ++i) {
    int temp = i;
    actions.Add(() => Execute(100100100 + temp));
}

To create 100 separate lambdas, you can create LINQ expression to call Execute, build constants one by one, and compile the lambdas. However, this is unlikely going to give you much performance improvement. Here is how you do it:

var exec = typeof(Test).GetMethod("Execute"); // <<== Use your type here
var actions = new List<Action>();
for (int i = 0 ; i != 100 ; i++) {
    var val = Expression.Constant(i+100100100);
    // This assumes that Execute(int) is static.
    // For non-static calls use a different overload.
    var call = Expression.Call(exec, val);
    var lambda = Expression.Lambda(typeof(Action), call, new ParameterExpression[0]);
    actions.Add((Action)lambda.Compile());
}

Here is a demo on ideone.

OTHER TIPS

Lambda expressions are evaluated at compile time, so the below code will not generate a 100 different functions.

I'm not sure what you mean by this statement. If you're trying to create 100 delegates, each bound to a different value of i, then you need to copy i into a temporary variable inside the for loop to ensure that the closures don't all refer to the same instance of i. (See dasblinkenlight's answer for details.)

But in this particular case, you can just use LINQ:

List<Action> actions = Enumerable.Range(0, 100)
    .Select(i => (Action)(() => Execute(100100100 + i)))
    .ToList();

Alternatively, if you prefer to use a loop and you're using .NET 4.5 or later, you can use foreach with Enumerable.Range:

List<Action> actions = new List<Action>();
foreach (int i in Enumerable.Range(0, 100))
    actions.Add(() => Execute(100100100 + i));
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top