2013-05-21 2 views
1

다음 코드는 의사 코드입니다. 이 함수가 Expresstion 형식을 받아 들일 수 있도록 만들고이 식을 컴파일하고 적절한 매개 변수로 호출 할 수있게하려고합니다.표현식과 위임을 C#

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는 Action, Action<int> 등이 될 수 있음). 매개 변수 d은 호출하기 위해 전송되는 동적 유형의 배열입니다.

하지만 코드 완성 방법을 모르겠습니다. 나는 그것을 구현하는 것이 쉽지 않을 것이라고 확신한다. 아마도 그것은 사실 일 수 없습니다. #

답변

3

정확한 서명을 알지 못하는 한 Invoke을 사용할 수 없습니다. 당신은, 그러나, 예를 들어, DynamicInvoke 사용할 수 있습니다 위의 dynamic은 아무 가치가 없다는 것을

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

주 - d은 단지뿐만 아니라 object[]을 수 있습니다.

다른, 약간 더 복잡한 접근 방식 - Func<object[]>로 컴파일하고 p가있다 p[n]과 식 (ExpressionVisitor) (원래 exp에서) "파라미터 n"을 대체 할을 다시 작성하는 것 단일 ParameterExpressionnConstantExpressionn입니다. 이것은 이라면 컴파일 된 람다를 저장하고 적극적으로 재사용 할 것입니다. 그러나 특정 시나리오에서는 호출 당 컴파일하므로 이점이 없습니다.

다음은 예제이지만, 주로 비슷한 시나리오의 독자에게는 적합하지만 컴파일 된 대리인은 다시 사용됩니다. 이 재 작성의 "장점"은 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); 
     } 
    } 
} 
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);