2017-12-15 12 views
2

나는 나의 ExpressionVisitor에서 내가 오버라이드 VisitMethodCall에 MethodCallExpression을 얻을하는 방법 인수에 대한 연산과 함께 MethodCallExpression을 컴파일하는 방법은 무엇입니까?

private static int Method(int n) 
{ 
    return n; 
} 

방법

있습니다. MethodCallExpression에는 다음이 포함

n => Method(2 + n) 

내가 Func을로 컴파일하고 다음과 같이 호출 할 :

func(3) 

을 그리고 그것은

5. 나는이 시도 반환해야합니다입니다 :

IEnumerable<ParameterExpression> parameters = expression.Arguments.Select(a => Expression.Parameter(a.Type, a.ToString())); 
    MethodCallExpression call = Expression.Call(expression.Method, parameters); 
    Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, call.Arguments.OfType<ParameterExpression>()); 
    var func = lambda.Compile(); 
    Console.WriteLine(func(3)); 

을 그리고 3이 아니라 5를 반환합니다.

왜냐하면 2 + x는 param 이름이고 3으로 바꿔야하기 때문입니다.

+1

왜 표현 방문자를 무시할 때 이와 비슷한 작업을 수행 하시겠습니까? – Evk

+0

방금 ​​교육 사례 일 뿐이며, 방문자의 외부에이 기능을 보냅니다. –

+1

다른 표현 방문자가 필요하다고 생각합니다. 해당 MethodCallExpression에서 매개 변수 (인수가 아님)를 \ 추출해야합니다. – Evk

답변

1

왜 이렇게 할 지 모르지만 어쨌든이 작업을 수행하려면 매개 변수 (인수가 아님)를 추출해야합니다. MethodCallExpression . 이를 위해 당신은 다음과 같이 표현 방문자를 남용 할 수

public class ParametersExtractorVisitor : ExpressionVisitor { 
    public IList<ParameterExpression> ExtractedParameters { get; } = new List<ParameterExpression>(); 
    protected override Expression VisitParameter(ParameterExpression node) { 
     ExtractedParameters.Add(node); 
     return base.VisitParameter(node); 
    } 
} 

그런 다음 코드에서 다음과 같이 사용 :

var visitor = new ParametersExtractorVisitor(); 
visitor.Visit(expression); 
MethodCallExpression call = Expression.Call(expression.Method, expression.Arguments); 
Expression<Func<Int32, Int32>> lambda = Expression.Lambda<Func<int, int>>(call, visitor.ExtractedParameters); 
var func = lambda.Compile(); 
Console.WriteLine(func(3)); 
+0

나는 이해했습니다! 나는 가까이에, 젠장! 고마워요! –

0

당신은 그것을 구현하는 방문자 필요하지 않습니다.
기본적으로 당신의 Method 기능은 MethodCallExpression

을 돌연변이에 의해 2

using System; 
using System.Linq.Expressions; 
using System.Reflection; 

namespace Test 
{ 
    class Program 
    { 
     static void Main(string[] args) { 
      var method = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.Public); 
      var parameter = Expression.Parameter(typeof(int), "n"); 
      var add = Expression.Add(Expression.Constant(2, typeof(int)), parameter); 
      var methodCallExpression = Expression.Call(null, method, add); 
      var lambda = Expression.Lambda<Func<int, int>>(methodCallExpression, parameter); 
      var func = lambda.Compile(); 

      Console.WriteLine(func(3)); 
     } 

     public static int Method(int n) => n; 
    } 
} 

나는 방문자를 사용하여 구현하는 것이의 상수 값과 람다에 전달 된 값의 추가 작업의 결과와 함께 제공되어야한다

using System; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 

namespace Test 
{ 

    class MethodCallVisitor : ExpressionVisitor 
    { 
     private readonly int toAdd; 

     public MethodCallVisitor(int toAdd) { 
      this.toAdd = toAdd; 
     } 

     protected override Expression VisitMethodCall(MethodCallExpression node) { 
      var add = Expression.Add(node.Arguments.First(), Expression.Constant(toAdd)); 

      return Expression.Call(node.Object, node.Method, add); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) { 
      var methodCallVisitor = new MethodCallVisitor(2); 
      var method = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.Public); 
      var parameter = Expression.Parameter(typeof(int), "n"); 
      var methodCallExpression = Expression.Call(null, method, parameter); 
      var lambda = Expression.Lambda<Func<int, int>>(methodCallExpression, parameter); 

      lambda = (Expression<Func<int, int>>)methodCallVisitor.Visit(lambda); 
      var func = lambda.Compile(); 

      Console.WriteLine(func(3)); 
     } 

     public static int Method(int n) => n; 
    } 
} 
+1

내 목표는이 방법을 시작하는 콘솔 시간에 인쇄하기 위해 한 가지 방법을 다른 방법으로 바꾸기 때문에 필요합니다. –

+0

OP에는 큰 표현 트리의 일부인 MethodCallExpression 만 있습니다. 그는 내가 이해하는 한이 방법 호출만으로 람다를 만들고 싶어한다. – Evk