我试图建立一个表达式,使调用LINQ的Any()方法,我似乎找不到正确的参数传递给Type.GetMethod()。
从文档来看,Any()似乎是作为Enumerable类的成员实现的,这似乎是有效的,因为它显示了名为"Any"的方法:
var enumerableType = typeof (Enumerable);
var foo = enumerableType.GetMethods().Where(m => m.Name == "Any").ToList();
当我使用名为"Any"的方法时,我得到一个AmbiguousMatchException。
在Enumerable中有两个Any()方法,一个接受IEnumerable参数,另一个接受IEnumerable参数和Func参数。我需要第二种类型,理论上,我所需要做的就是传递一个包含这两种类型的数组:
var bar = enumerableType.GetMethod("Any", new[] { typeof(IEnumerable<>), typeof(Func<,>) });
但是这总是返回null。
我做错了什么?
var foo = enumerableType.GetMethods(BindingFlags.Static | BindingFlags.Public)
.First(m => m.Name == "Any" && m.GetParameters().Count() == 2);
如果您想明确地确保您匹配了接受IEnumerable<>
和Func<,>
参数的重载,您可以使用以下方法(改编自此回答):
var enumerableType = typeof(Enumerable);
var bar =
(
from m in enumerableType.GetMethods(BindingFlags.Static | BindingFlags.Public)
where m.Name == "Any"
let p = m.GetParameters()
where p.Length == 2
&& p[0].ParameterType.IsGenericType
&& p[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
&& p[1].ParameterType.IsGenericType
&& p[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>)
select m
).SingleOrDefault();
感谢@JonSkeet为我指出了正确的方向,这里有几个一行:
var any = typeof(Enumerable).GetMethods().FirstOrDefault(m => m.Name == "Any" && m.IsGenericMethodDefinition && m.GetParameters().Length == 1 && m.GetParameters()[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(m.GetGenericArguments()[0]));
var anyWhere = typeof(Enumerable).GetMethods().FirstOrDefault(m => m.Name == "Any" && m.IsGenericMethodDefinition && m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == typeof(IEnumerable<>).MakeGenericType(m.GetGenericArguments()[0]) && m.GetParameters()[1].ParameterType == typeof(Func<,>).MakeGenericType(m.GetGenericArguments()[0], typeof(bool)));
由于Enumerable.Any
是在编译时可访问的方法,因此可以使用以下基于delegate
的简单且类型安全的方法:
var anyMethodInfo = ((Func<IEnumerable<object>, Func<object, bool>, bool>)Enumerable.Any)
.Method.GetGenericMethodDefinition();
您可以自由地将delegate的签名匹配到您想要获得MethodInfo
的方法的任何重载