表达式树的问题 - 如何将实例方法转换为Func

时间:2018-02-02 09:24:38

标签: c# expression

我有一些代码,当前使用反射来调用类的方法,类和方法名称为字符串。每个类的所有方法都有相同的签名 - 取字符串,字符串,IDictionary和返回bool。

我尝试做的是用表达式构建它并基本上将Func缓存在字典中,因此反射仅在它第一次被调用时完成。但是我对如何做到这一点感到有点困惑 - 我现在有以下代码

public Func<string, string, IDictionary<string, string>, bool> GetFunc(string className, string methodName)
{
    lock (_locker)
    {
        if (!_criteriaCache.ContainsKey(className) || !_criteriaCache[className].ContainsKey(methodName))
        {
            object o = Assembly.GetExecutingAssembly().CreateInstance(className);
            var instance = Expression.Parameter(o.GetType(), "instance");
            var value = Expression.Parameter(typeof (string), "value");
            var compareValue = Expression.Parameter(typeof(string), "compareValue");
            var parameters = Expression.Parameter(typeof(IDictionary<string,string>), "parameters");

            var method = o.GetType().GetMethod(methodName,
                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);

            Func<string, string, IDictionary<string, string>, bool> result =
                Expression.Lambda<Func<string, string, IDictionary<string, string>, bool>>(
                    Expression.Call(instance,method,new List<Expression> { value,compareValue,parameters })).Compile();
            if (!_criteriaCache.ContainsKey(className))
                _criteriaCache.Add(className,new Dictionary<string, Func<string, string, IDictionary<string, string>, bool>>());

            _criteriaCache[className].Add(methodName,result);
        }
    }
    return _criteriaCache[className][methodName];
}

但是我在Expression.Call函数上遇到错误,说&#39;为lambda声明提供的参数数量不正确&#39;。我在这里缺少什么?

1 个答案:

答案 0 :(得分:2)

您需要提供所有外部ParameterExpression声明作为Expression.Lambda的最终参数。目前你没有给它任何。但是 - 目前还不清楚你对instance的期望是什么,因为你的lambda 没有一个实例。您可能认为instanceExpression.Constant(o)

var instance = Expression.Constant(o);
...
var result =
    Expression.Lambda<Func<string, string, IDictionary<string, string>, bool>>(
        Expression.Call(instance, method, new List<Expression> {
            value, compareValue, parameters }),
        value, compareValue, parameters).Compile();

看起来您正在对参数进行直接传递 - 但在这种情况下,这可能会更简单:

var result = (Func<string, string, IDictionary<string, string>, bool>)
      Delegate.CreateDelegate(
          typeof(Func<string, string, IDictionary<string, string>, bool>),
          o, method);