2012-09-20 1 views
1

알아낼 수없는 람다 식 트리 문제가 있습니다. 동적 linq Select 문을 만들려고합니다. 동적 람다 선택 식

나는 동적 저장소가 여기에 만든이 :이

private static dynamic GetRepository(Type type) 
{ 
    dynamic repository = typeof(IFactory).GetMethod("Create").MakeGenericMethod(typeof(IRepository<>).MakeGenericType(type)).Invoke(ObjectFactory.Instance, new object[] { }); 
    return repository; 
} 

은 내가 컴파일시 x와 SomeProperty를 모르는이 만 호출해야합니다. SomeProperty 이름이있는 PropertyInfo propertyInfo와 x 유형이있는 objectType을 가지고 있습니다. 그것은이 제외 목표 1에 실패 getMethod 메소드 (문자열 이름)에서

System.Reflection.AmbiguousMatchException

이 코드는 :

private SomeObject CreateSomeObject (PropertyInfo propertyInfo, Type objectType) 
{ 
    var param = Expression.Parameter(objectType, "x"); 
    MemberExpression expression = Expression.PropertyOrField(param, propertyInfo.Name); 

    //Goal 1: var selectExpression = Expression.Lambda<Func<objectType, object>>(expression, param); 
    var selectExpression = typeof(Expression).GetMethod("Lambda").MakeGenericMethod(typeof(Func<,>) 
    .MakeGenericType(objectType, typeof(object))) 
    .Invoke((object)null, new object[] { expression, param }); 

    // Goal 2: List<object> list = GetRepository(objectType).FindAllQuery().Select(x => x.SomeProperty).ToList(); 
    List<object> list = GetRepository(objectType).FindAll().Select(selectExpression); 
} 

어떻게이 문제를 해결하려면?

업데이트 1 : 나는 람다 방법을 선택하는 방식을 변경 한

는 방법은 'PARAM'매개 변수를 포장하고 나는 '표현'에 개체 변환기를 추가했습니다.

private SomeObject CreateSomeObject (PropertyInfo propertyInfo, Type objectType) 
{ 
    var param = Expression.Parameter(objectType, "x"); 
    Expression expression = Expression.Convert(Expression.PropertyOrField(param, propertyInfo.Name), typeof(object)); 

    //Goal 1: var selectExpression = Expression.Lambda<Func<objectType, object>>(expression, param); 
    var selectExpression = typeof(Expression).GetMethods().First(m => m.Name == "Lambda" && m.IsGenericMethod) 
    .MakeGenericMethod(typeof(Func<,>) 
    .MakeGenericType(objectType, typeof(object))) 
    .Invoke((object)null, new object[] { expression, new [] { param }}); 

    // Goal 2: List<object> list = GetRepository(objectType).FindAllQuery().Select(x => x.SomeProperty).ToList(); 
    List<object> list = GetRepository(objectType).FindAll().Select(selectExpression); 
} 

그러나 내가 목표 2 (Microsoft.CSharp.RuntimeBinder.RuntimeBinderException)에서이 예외 얻을 알고 :

'System.Collections.Generic.List가'에 대한 정의를 포함하지 않는 '를 선택 '

이것은 System.Linq에 정의되어 있으며 확장 방법이기 때문에 부분적으로 적합합니다. 어떻게 작동합니까? Expression 유형 (이에 AmbiguousMatchException)에 정의 Lambda 호출 방법 18가 있으므로

답변

3

예외를 발생 코드

typeof(Expression).GetMethod("Lambda") 

이다.

GetMethod(string methodName)은 과부하가 없을 때 적합합니다. 이 경우에는 GetMethods()을 사용하고 필요한 필터를 걸러냅니다. 귀하의 경우에는

는 오른쪽 과부하

Expression.Lambda<TDelegate>(Expression body, params ParameterExpression[] parameters) 

당신은 매개 변수와 그 종류의 수를 확인하여 적절한 과부하를 검증하는 기능을 쓸 수 있습니다,하지만 난 쉬운 대안을 발견하여 방법을 필터링

System.Linq.Expressions.Expression`1[TDelegate] Lambda[TDelegate](System.Linq.Expressions.Expression, System.Linq.Expressions.ParameterExpression[]) 

또한 매개 변수 (new object[] { expression, param })를 전달하는 방법에 문제가있다 : 우리의 경우에있는 .ToString() 표현. 두 번째 매개 변수는 ParameterExpression이 아니고 ParameterExpression[] (배열)이므로 param 대신 new[]{param}을 전달해야합니다. 정규 코드에서 호출 할 때는 params ParameterExpression[]으로 정의되어 있기 때문에 작동합니다.

결론적으로, 다음 코드는 귀하의 경우에 작동합니다 : 사실

const string methodSignature = 
    "System.Linq.Expressions.Expression`1[TDelegate] Lambda[TDelegate]" + 
    "(System.Linq.Expressions.Expression, System.Linq.Expressions.ParameterExpression[])"; 

var lambdaMethod = typeof (Expression).GetMethods() 
    .Single(mi => mi.ToString() == methodSignature); 

var funcType = typeof (Func<,>).MakeGenericType(objectType, typeof (object)); 

var genericLambda = lambdaMethod.MakeGenericMethod(funcType); 

var selectExpression = genericLambda.Invoke(null, new object[] { expression, new[] { param } }); 
+0

을 http://msdn.microsoft.com/en- (['Expression'에'Lambda'라는 18 가지 방법이있다]는 us/library/system.linq.expressions.expression.lambda.aspx)와 그 중 6 개가 일반적입니다. 따라서 코드는 일반적인 코드 중 하나를 반환하지만 가장 적합한 코드는 아닌 것으로 보입니다. – svick

+0

고마워. 이제 'System.Linq.Expressions.TypedParameterExpression'형식의 개체를 'System.Linq.Expressions.ParameterExpression []'형식으로 변환 할 수 없습니다. Invoke 메서드에서. –

+0

@svick : 그럼 올바른 것을 선택하려면 어떻게해야합니까? –