在C#中运行时构造一个函数

时间:2013-08-25 15:48:53

标签: c# lambda runtime compile-time anonymous-methods

Lambda表达式在编译时进行评估,因此下面的代码不会生成100个不同的函数。是否有一种简单的机制来实现上述效果?我意识到这不是非常有效的表现。

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

2 个答案:

答案 0 :(得分:2)

  

Lambda表达式在编译时进行评估,因此下面的代码不会生成100个不同的函数。

我不确定你的意思是什么意思。如果您尝试创建100个委托,每个委托绑定到i的不同值,则需要将i复制到for循环内的临时变量中以确保关闭并非都引用i的同一个实例。 (看到 dasblinkenlight对细节的回答。)

但在这种特殊情况下,你可以使用LINQ:

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

或者,如果您更喜欢使用循环并且使用的是.NET 4.5或更高版本,则可以将foreachEnumerable.Range一起使用:

List<Action> actions = new List<Action>();
foreach (int i in Enumerable.Range(0, 100))
    actions.Add(() => Execute(100100100 + i));

答案 1 :(得分:2)

此代码关闭修改后的变量,因此它不会按照您的意愿执行。您需要为i的值添加临时变量,如下所示:

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

要创建100个单独的lambda,可以创建LINQ表达式来调用Execute,逐个构建常量,并编译lambdas。但是,这不太可能给您带来很大的性能提升。这是你如何做到的:

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