简体   繁体   English

如何在C#/ .NET中使用LINQ表达式树调用lambda

[英]How to call a lambda using LINQ expression trees in C# / .NET

I want to use expression trees to dynamically create a method to call a lambda. 我想使用表达式树动态创建一个方法来调用lambda。 The following code runs fine for the first call to the ComposeLambda function, but the second call fails with the following error message. 第一次调用ComposeLambda函数时,以下代码运行正常,但第二次调用失败,并显示以下错误消息。

Incorrect number of arguments supplied for call to method 'Int32 lambda_method(System.Runtime.CompilerServices.Closure, Int32)' 为调用方法'Int32 lambda_method(System.Runtime.CompilerServices.Closure,Int32)提供的参数数量不正确

{
    Func<int, int> innerLambda = i => i + 1;    
    var composedLambda = ComposeLambda(innerLambda);
    Console.WriteLine(composedLambda.DynamicInvoke(0));
    var composedLambda2 = ComposeLambda(composedLambda);
    Console.WriteLine(composedLambda2.DynamicInvoke(0));
}

private static Delegate ComposeLambda(Delegate innerLambda)
{
    Func<int, int> outerLambda = i => i + 2;
    var parameter = Expression.Parameter(typeof (int));
    var callInner = Expression.Call(innerLambda.GetMethodInfo(), parameter);
    var callOuter = Expression.Call(outerLambda.GetMethodInfo(), callInner);
    var composedLambdaType = typeof (Func<,>).MakeGenericType(typeof (int), typeof (int));
    var composedLambdaExpression = Expression.Lambda(composedLambdaType, callOuter, parameter);
    var composedLambda = composedLambdaExpression.Compile();
    return composedLambda;
}

How can I get and pass on this closure object? 如何获取并传递此闭包对象?

Don't use Expression.Call(innerLambda.GetMethodInfo(), ...) , that's just asking for trouble. 不要使用Expression.Call(innerLambda.GetMethodInfo(), ...) ,这只是在寻找麻烦。 Invoke the delegate instead - you have no business messing around with the delegate's "method" - not only do you lose the target (quite important in instance methods), but you're also violating privacy (anonymous methods are internal or private, for example). 相反,调用委托 - 你没有业务搞乱委托的“方法” - 你不仅失去了目标(在实例方法中非常重要),而且你也违反了隐私(匿名方法是内部或私人的,例如)。

And in this case, you didn't pass the closure parameter to the method :) This should be rather obvious from the error message - it shows you the signature of the actual method (which includes the closure). 在这种情况下,您没有将closure参数传递给方法:)这应该从错误消息中显而易见 - 它向您显示实际方法的签名(包括闭包)。

If you use Expression.Invoke (as you should with delegates), it works as expected: 如果您使用Expression.Invoke (就像您应该使用委托),它可以按预期工作:

void Main()
{
    Func<int, int> innerLambda = i => i + 1;    
    var composedLambda = ComposeLambda(innerLambda);
    Console.WriteLine(composedLambda.DynamicInvoke(0));
    var composedLambda2 = ComposeLambda(composedLambda);
    Console.WriteLine(composedLambda2.DynamicInvoke(0));
}

private static Delegate ComposeLambda(Delegate innerLambda)
{
    Func<int, int> outerLambda = i => i + 2;
    var parameter = Expression.Parameter(typeof (int));

    var callInner = Expression.Invoke(Expression.Constant(innerLambda), parameter);
    var callOuter = Expression.Invoke(Expression.Constant(outerLambda), callInner);
    var composedLambdaType = typeof (Func<,>).MakeGenericType(typeof (int), typeof (int));
    var composedLambdaExpression = Expression.Lambda(composedLambdaType, callOuter, parameter);
    var composedLambda = composedLambdaExpression.Compile();
    return composedLambda;
}

In addition to this, if you know the proper delegate type at compile-time, don't use Delegate . 除此之外,如果您在编译时知道正确的委托类型,请不要使用Delegate In this case, it's pretty trivial to use Func<int, int> , which you can then invoke as composedLambda2(0) , for example: 在这种情况下,使用Func<int, int>非常简单,然后可以将其作为composedLambda2(0)调用,例如:

private static Func<int, int> ComposeLambda(Func<int, int> innerLambda)
{
  Func<int, int> outerLambda = i => i + 2;
  var parameter = Expression.Parameter(typeof (int));

  var callInner = Expression.Invoke(Expression.Constant(innerLambda), parameter);
  var callOuter = Expression.Invoke(Expression.Constant(outerLambda), callInner);

  var composedLambdaExpression = Expression.Lambda<Func<int, int>>(callOuter, parameter);
  return composedLambdaExpression.Compile();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM