无法在表达式<func <...>&gt;之间转换和Func&lt; ...&gt;

时间:2016-01-14 01:18:59

标签: c# .net generics reflection lambda

我试图呼叫的方法(第三方,无法更改)需要Func<TResult>。使用反射我试图做一个例如Func<Task<IEnumerable<Person>>>但我无意中创建了Expression<Func<Task<IEnumerable<Person>>>>。反思的原因是人是任意的,可以是任何类型,取决于如何/何时调用它。

// 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] });

当我稍后使用lambda时,我得到了异常

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<>?我似乎无法找到正确的方法。

谢谢

1 个答案:

答案 0 :(得分:5)

您正在寻找.Compile()方法,这正是如此。

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

Expression.Lambda(body).Compile()