我正在尝试使用反射返回正确的"Where"扩展方法,以便构建自定义表达式。我已经尝试了几种方法,但我得到的最接近的方法抛出了一个异常:"mscorlib 中发生了类型为'System.Reflection.AmbiguousMatchException'的未处理异常.dll"
我知道这是因为在 Enumrable 类中定义了两个 Where 方法 - 但是我如何返回仅使用
Func<T, bool>.
我目前拥有的是:
var collectionType = typeof(TSub);
Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionType);
MethodInfo methodInfo =
typeof(Enumerable)
.GetMethod("Where")
.MakeGenericMethod(collectionType);
我也试过(这个返回空):
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { typeof(TSub )});
和(也返回空值)
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { collectionType })
和(这个返回相同的模棱两可异常)
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public | BindingFlags.Static)
有人可以帮忙吗?
谢谢
在我看来,目前的答案,包括公认的答案,远比必要的复杂得多。如果你有一个可以在编译时使用的类型T
,你可以得到如下MethodInfo
:
Func<IEnumerable<T>, Func<T, bool>, IEnumerable<T>> whereDelegate = Enumerable.Where;
MethodInfo whereMethodInfo = whereDelegate.Method;
作为额外的奖励,这是强类型。只有当可以解析Enumerable.Where
时,它才会编译,而不是任何查找字符串"Where"
:如果您不小心键入"Wehre"
,则可以编译,但在运行时会失败。
我相信有更简单的方法,但这里有一个:
typeof(Enumerable).GetMethods()
.Single(method => method.Name == "Where"
&& method.GetParameters()
.ElementAt(1)
.ParameterType
.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericMethod(typeof(TSub))
不过这有点脆弱(想想Microsoft在 .NET 的未来版本中添加更多重载)。也许更强大(但更可怕;肯定有更好的方法)是:
var methods = from method in typeof(Enumerable).GetMember("Where")
.OfType<MethodInfo>()
let typeArgs = method.GetGenericArguments()
where typeArgs.Length == 1
let typeArg = typeArgs.Single()
where !typeArg.GetGenericParameterConstraints().Any()
let seqtype = typeof(IEnumerable<>).MakeGenericType(typeArg)
where method.ReturnType == seqtype
let expectedParams = new[]
{
seqtype,
typeof(Func<,>).MakeGenericType(typeArg, typeof(bool))
}
where method.GetParameters()
.Select(parameter => parameter.ParameterType)
.SequenceEqual(expectedParams)
select method.MakeGenericMethod(typeof(TSub));
var result = methods.Single();
使用模板类型 T,这应该可以工作:
var methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public | BindingFlags.Static, new Type[]{ typeof(IEnumerable<T>), typeof(Func<T, bool>) });
Where 方法采用两个参数:IEnumerable 和比较函数。
我认为区分这两个重载的最简单方法是:
var whereMethod = typeof(Enumerable).GetMethods()
.Single(m => m.Name == "Where" && m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericType(typeof(TSub));