2016-01-14 107 views
0

我试图调用的一种方法(第三方,无法更改)需要Func<TResult>。使用反射我试图做一个例如Func<Task<IEnumerable<Person>>>但我无意中创建Expression<Func<Task<IEnumerable<Person>>>>。反思的原因是,这个人是任意的,可以是任何类型,这取决于如何/何时被调用。无法在表达式<Func<...>>和Func <...>之间转换

// trying to mimic this hard-code:() => TaskEx.FromResult(Enumerable.Empty<Person>()) 
//var enumerableType = typeof(Person); //potentially 

var empty = (typeof(Enumerable)).GetMethod("Empty"); 
var genereicEmpty = empty.MakeGenericMethod(enumerableType); 
var emptyEnumerable = genereicEmpty.Invoke(null, null); 

var fromResult = typeof (TaskEx).GetMethod("FromResult"); 
var genericFromResult = fromResult.MakeGenericMethod(genereicEmpty.ReturnType); 

var enumerableTask = genericFromResult.Invoke(null, new [] {emptyEnumerable}); 

var functype = typeof(Func<>).MakeGenericType(genericFromResult.ReturnType); 
var body = Expression.Constant(enumerableTask); 
var lambdaType = typeof(Expression).GetMethods() 
    .Where(x => x.Name == "Lambda") 
    .Where(x => x.GetParameters().Length == 2) 
    .Where(x => x.GetParameters()[1].ParameterType == typeof(ParameterExpression[])) 
    .Single(x => x.IsGenericMethod); 
var genericLambdaType = lambdaType.MakeGenericMethod(functype); 
var lambda = genericLambdaType.Invoke(null, new object[] { body, new ParameterExpression[0] }); 

当我使用拉姆达后,我得到的异常

Exception thrown: 'System.ArgumentException' in mscorlib.dll 

Additional information: Object of type 'System.Linq.Expressions.Expression`1[System.Func`1[System.Threading.Tasks.Task`1[System.Collections.Generic.IEnumerable`1[DC.Dataloader.Models.Person]]]]' cannot be converted to type 'System.Func`1[System.Threading.Tasks.Task`1[System.Collections.Generic.IEnumerable`1[DC.Dataloader.Models.Person]]]'. 

难道还有比Expression.Lambda更好的方式来建立对飞一个Func<>?我似乎无法找到正确的方法来做到这一点。

谢谢

回答

5

您正在寻找的.Compile()方法,它正是这么做的。

附注:
您不需要使用Reflection调用Expression API;你可以使用非通用的Expression.Lambda(),它仍然会返回一个Func<T>

Expression.Lambda(body).Compile() 
+0

完美!不能相信它在我的鼻子下。很高兴摆脱'typeof(Func <>)'和'lambdaType/genericLambdaType'查询。谢谢 –

相关问题