1

私は擬似コードである以下のコードを持っています。この関数が Expression 型を受け入れ、この式をコンパイルして、適切なパラメーターで呼び出すことができるようにしたいと考えています。

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はアクションタイプだと思います。(T はActionAction<int>など)。パラメータdは動的型の配列で、invoke に送信されます。

しかし、コードを完成させる方法がわかりません。それを実装するのは簡単ではないと確信しています。おそらく、C# では当てはまりません。

4

2 に答える 2

3

Invoke正確な署名を知らなければ使用できません。ただし、DynamicInvokeたとえば次のように使用できます。

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

dynamic上記の は目的を果たさないことにd注意してくださいobject[]

もう少し複雑なもう 1 つのアプローチは、それを としてコンパイルし、式( )をFunc<object[]>書き直して、(元の からの) ExpressionVisitor"パラメータ n" を に置き換えることです。これは、コンパイルされたラムダを保存して積極的に再利用する場合に有利です。ただし、特定のシナリオでは、呼び出しごとにコンパイルしているため、これには利点がありません。expp[n]pParameterExpressionnConstantExpressionn

以下に例を示しますが、これは主に、同様のシナリオで、コンパイルされたデリゲートが再利用される後の読者を対象としています。この書き直しの「利点」は、 の署名Delegate.DynamicInvokeを保持しながら、 のパフォーマンスへの影響を回避できることです。ただし、これはデリゲートが複数回使用されている場合にのみ役立ちます。現時点では (呼び出しごとにコンパイルされます)、ここでの「作業」のほとんどは、式コンパイルと JIT コンパイルになります。object[] => objectDelegate.DynamicInvoke

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 に答える