首页 > 解决方案 > 将动作转换为 LambdaExpression

问题描述

我正在使用 NRules 并尝试从数据库加载规则。

为此,我必须使用反射来生成表达式。

public class Product
{
     public string Attribute1 { get; }
     public List<int> Category { get; set; }   
     public void AddCategory (int category){
          this.Category.Add(category);
     }
}

using NRules.RuleModel;
using NRules.RuleModel.Builders;

var builder = new RuleBuilder();
//some logic for buildin lefthand side
Expression<Action<IContext, Product>> action = (ctx, product) => product.AddCategory(25);
builder.RightHandSide().Action(action);

Expression<Action<IContext, Product>> action = (ctx, product) => product.AddCategory(25);我的目标是在运行时生成“ ”。我认为这样做的唯一方法是使用反射。因为我正在从数据库中读取一些值。

我可以使用反射生成动作:

Type actionType = typeof(Action<>).MakeGenericType(new Type[] { typeof(IContext),      
Type.GetType(actualModelName) });
MethodInfo eventMethodInfo = type.GetMethod("AddCategory");
Action actionFromReflection  = (Action)Delegate.CreateDelegate(actionType, eventMethodInfo);

但是 NRules 方法需要一个 LambdaExpression 作为参数。

如何将“actionFromReflection”转换为 LambdaExpression?

LambdaExpression le = actionFromReflection  ???

标签: c#reflectiondelegatesaction

解决方案


一个委托是指真正编译的代码,而一个 Lambda 表达式是一个表达式树,接近源代码,而不是文本形式。你可以打电话给你的代表,但没有别的。从 IL 代码创建源代码将是反汇编程序的工作。

使用反射意味着“使用已经编译的东西”,这与在运行时创建它相反。所以这是错误的做法。

要在运行时创建 LambdaExpression,您可以执行类似的操作

        ParameterExpression ctx = Expression.Parameter(typeof(Context), "ctx");
        ParameterExpression product = Expression.Parameter(typeof(Product), "product");

        LambdaExpression lambdaExpr = Expression.Lambda(
            /* your actual code, depending on what you want to do */
                Expression.Add(
                ctx,
                Expression.Constant(1)
            ),
            new List<ParameterExpression>() { ctx, product })

实际上这个示例确实构建了 ctx => ctx +1 如果你没有返回值,你可能有一个 Expression.Call。你必须进一步调查,如何表达你想要的,作为一个表达树。这是一个广泛的话题。

您可以投射的 LambdaExpression:

var expr = (Expression<Action<ctx, product>>) lambdaExpr;

推荐阅读