【问题标题】:Expression and delegate in c#c#中的表达式和委托
【发布时间】:2013-05-21 06:33:37
【问题描述】:

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

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 可以是ActionAction&lt;int&gt; 等)。参数d是动态类型的数组,发送给invoke。

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

【问题讨论】:

    标签: c# dynamic delegates lambda expression


    【解决方案1】:

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

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

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

    另一种稍微复杂一点的方法 - 将其编译为 Func&lt;object[]&gt;,然后重写表达式 (ExpressionVisitor) 以将“参数 n”(来自原始 exp)替换为 @ 987654330@,其中p 是单个ParameterExpressionnConstantExpressionn如果您要存储并积极地重用已编译的 lambda,这可能是有利的。但是在您的特定场景中,您是按调用编译的,所以这没有任何好处。

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

    【讨论】:

      【解决方案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);
      

      【讨论】:

        猜你喜欢
        • 2011-01-14
        • 2015-03-06
        • 2012-08-27
        • 1970-01-01
        • 2010-12-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多