2017-11-28 3 views
1

Expression 유형의 형태로 Expression<Func<...,...,...,TResult>> (임의이지만 고정 된 수의 매개 변수) 인스턴스를받습니다. 예컨대주어진 fram 결과 식을 계산하는 가장 빠른 방법

:

Expression<Func<int,int,int>> adderExpression = (a,b) => a+b; 
LambdaExpression receivedExpression = adderExpression; 
//Later on, I get only the receivedExpression variable and an array of values for which I have to compute: 
var values = new object[] {3, 4}; 
var result = receivedExpression.Compile().DynamicInvoke(values); 

receivedExpression 변수 I 컴파일 된 식을 적용한 결과를 산출 할 필요가있는 개체 값의 배열되는 I가 액세스 할 수있는 유일한 방법.

receivedExpression은 변경되지 않습니다. 한 번 가져 오면 변경되지 않습니다.

내 상황에 따라 result 변수를 계산하는 가장 빠른 방법은 무엇입니까? 이 경우에는 DynamicInvoke이 매우 느리기 때문에 결과를 계산하는 더 빠른 방법이 있는지 궁금합니다.

var rec = receivedExpression.Compile(); 
var f = (object[] p) => (object)rec.Invoke((type0)p[0],(type1)p[1],...); 

, 당신은 (알 수없는)을 변환하는 데 우선해야합니다

+0

있는 방법'컴파일이 없기 때문에 귀하의 코드는 컴파일되지 않습니다 '표현식 ' – NetMage

+1

아마도'LambdaExpression receivedExpression'이어야할까요? – Phaeze

+0

관련된 유형, 특히 반환 유형을 알고 있습니까? – NetMage

답변

1

당신은 인수의 배열을 효과적으로 동적으로 동등한를 창조하는이 Expression 전달 호출 Invoke를 사용하여 컴파일 된 대리자를 만들 수 있습니다 receivedExpressionobject의 반환 형식은 그래서 당신은 강력한 형식의 대리자를 만들 수 있습니다

var fr = Expression.Lambda(Expression.Convert(receivedExpression.Body, typeof(object)), receivedExpression.Parameters); 

그런 다음 당신은 람다에 대한 Expression을 만들 수 있습니다 object[]을 사용하고 고정 된 숫자와 유형의 인수를 사용하여 람다를 호출합니다.

먼저 람다에 대한 매개 변수가 필요합니다 다음

var arg = Expression.Parameter(typeof(object[])); 

당신이 receivedExpression에 전달할 올바른 유형이 object[] 매개 변수의 각 구성원을 변환해야합니다 : 다음

var args = values.Select((v, i) => Expression.Convert(Expression.ArrayIndex(arg, Expression.Constant(i)), v.GetType())).ToArray(); 

새로운 람다를 만들 수 있습니다 :

var frs = Expression.Lambda(Expression.Invoke(fr, args), arg); 

그런 다음 당신은 Expression에 통과 포함하는 람다를 컴파일 :

var frsc = (Func<object[], object>)frs.Compile(); 

마지막으로, 당신은 전화 새로운 람다를 사용할 수 receivedExpression 효율적 :

object result = frsc.Invoke(values); 
+0

좋은 사람! Invoke보다 훨씬 빠른 방법이 있는지 궁금합니다. 그럼에도 불구하고 귀하의 접근 방식은 ~ 709ns (DynamicInvoke 사용)에서 56ns (귀하의 방법 사용)로 이동합니다. –

+0

'Invoke '는 컴파일러가 정규 함수 호출을'Expression' 트리로 변환하는 방법입니다. 그래서 가능한 한 효율적이라고 생각합니다. 'Func <>'에 대한 리터럴 호출을 검사하면 IL에서 'Invoke'를 사용하여이를 보여줍니다. – NetMage

관련 문제