1

我有下面的代码是伪代码。我想让这个函数可以接受一个表达式类型,编译这个表达式并用适当的参数调用它。

public static void f<T>(Expression<T> exp, params dynamic[] d)
{
    Console.WriteLine("begin");
    exp.Compile().Invoke(d[0],d[1].....);//this is pseudo-code

    Console.WriteLine("end");
}

我确定 T 是 Action 类型。(T 可以是Action,Action<int>等)。参数d是一个动态类型的数组,发送给invoke。

但我不知道如何完成代码。我敢肯定这并不容易实现。也许在c#中不可能是真的

4

2 回答 2

3

Invoke除非您知道确切的签名,否则您不能使用。但是,您可以使用DynamicInvoke,例如:

((Delegate)exp.Compile()).DynamicInvoke(d);

请注意,dynamic上面的 没有任何用途 -d也可以object[]

另一种稍微复杂的方法 - 将其编译为 a Func<object[]>,并重新编写表达式 ( ExpressionVisitor) 以将“参数 n”(来自原始exp)替换为,p[n]其中p是单个ParameterExpression并且n是 a ConstantExpression如果您要存储并积极重用已编译的 lambda,n这可能是有利的。但是在您的特定情况下,您是按调用编译的,所以这没有任何好处。

这是一个例子,但这主要是为以后有类似场景的读者准备的,但是编译的委托被重用;这种重写的“优点”是它避免了对性能的影响Delegate.DynamicInvoke,同时保留了; 的object[] => object签名Delegate.DynamicInvoke。但这只有在多次使用委托时才有用。目前(每次调用编译)这里的大部分“工作”都将在表达式编译和 JIT 编译中进行。

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
static class Program {
    static void Main() {
        Expression<Func<int, float, double>> exp = (i, f) => i * f;
        var func = CompileToBasicType(exp);

        object[] args = { 3, 2.3F };
        object result = func(args); // 6.9 (double)
    }

    static Func<object[], object> CompileToBasicType(LambdaExpression exp) {
        ParameterExpression arg =
            Expression.Parameter(typeof(object[]), "args");
        Dictionary<Expression, Expression> lookup =
            new Dictionary<Expression, Expression>();
        int i = 0;
        foreach (var p in exp.Parameters) {
            lookup.Add(p, Expression.Convert(Expression.ArrayIndex(
                arg, Expression.Constant(i++)), p.Type));
        }
        var body = Expression.Convert(
            new ReplaceVisitor(lookup).Visit(exp.Body), typeof(object));
        return Expression.Lambda<Func<object[], object>>(body, arg).Compile();
    }
    class ReplaceVisitor : ExpressionVisitor {
        private readonly Dictionary<Expression, Expression> lookup;
        public ReplaceVisitor(Dictionary<Expression, Expression> lookup) {
            if (lookup == null) throw new ArgumentNullException("lookup");
            this.lookup= lookup;
        }
        public override Expression Visit(Expression node) {
            Expression found;
            return lookup.TryGetValue(node, out found) ? found
                : base.Visit(node);
        }
    }
}
于 2013-05-21T06:48:57.137 回答
2
public static void F<T>(Expression<T> exp, params object[] d)
{
    Console.WriteLine("begin");

    var del = exp.Compile() as Delegate;
    del.DynamicInvoke(d);

    Console.WriteLine("end");
}

接着:

F<Action<int>>(i => Console.WriteLine(i), 5);

或者:

F<Action<string, int>>((s, i) => Console.WriteLine("{0} : {1}", s, i), "Hello", 5);
于 2013-05-21T06:51:26.593 回答