如何在C#/.NET中使用LINQ表达式树调用lambda [英] How to call a lambda using LINQ expression trees in C# / .NET

查看:66
本文介绍了如何在C#/.NET中使用LINQ表达式树调用lambda的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用表达式树动态创建一个调用lambda的方法.对于第一次调用ComposeLambda函数,以下代码运行良好,但是第二次调用失败,并显示以下错误消息.

I want to use expression trees to dynamically create a method to call a lambda. The following code runs fine for the first call to the ComposeLambda function, but the second call fails with the following error message.

为调用方法'Int32提供的参数数量不正确 lambda_method(System.Runtime.CompilerServices.Closure,Int32)'

Incorrect number of arguments supplied for call to method '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?

推荐答案

不要使用Expression.Call(innerLambda.GetMethodInfo(), ...),这只是在麻烦.而是调用委托-您无需费心处理委托的方法"-不仅会丢失目标(在实例方法中非常重要),而且还会侵犯隐私(例如,匿名方法是内部方法或私有方法) ).

Don't use Expression.Call(innerLambda.GetMethodInfo(), ...), that's just asking for trouble. 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).

如果您使用Expression.Invoke(与委托一起使用),它将按预期工作:

If you use Expression.Invoke (as you should with delegates), it works as expected:

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;
}

除此之外,如果您在编译时知道正确的委托类型,请不要使用Delegate.在这种情况下,使用Func<int, int>非常简单,然后可以将其作为composedLambda2(0)调用,例如:

In addition to this, if you know the proper delegate type at compile-time, don't use Delegate. In this case, it's pretty trivial to use Func<int, int>, which you can then invoke as composedLambda2(0), for example:

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();
}

这篇关于如何在C#/.NET中使用LINQ表达式树调用lambda的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆