我试图使用反射返回正确的“Where”扩展方法,以构建自定义Expression。我尝试了几种方法,但是我得到的最接近,抛出异常: “mscorlib.dll中发生了'System.Reflection.AmbiguousMatchException'类型的未处理异常”
我知道这是因为在Enumrable类中定义了两个Where方法 - 但是如何返回仅使用
谓词的Where方法 Func<T, bool>.
目前我所拥有的是:
var collectionType = typeof(TSub);
Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionType);
MethodInfo methodInfo =
typeof(Enumerable)
.GetMethod("Where")
.MakeGenericMethod(collectionType);
我也尝试过(这个返回null):
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { typeof(TSub )});
和(也返回null)
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { collectionType })
和(这个返回相同的模糊异常)
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public | BindingFlags.Static)
有人可以帮忙吗?
由于
答案 0 :(得分:1)
我确信有更简单的方法,但这里有一个:
typeof(Enumerable).GetMethods()
.Single(method => method.Name == "Where"
&& method.GetParameters()
.ElementAt(1)
.ParameterType
.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericMethod(typeof(TSub))
虽然这有点脆弱(想想微软在未来的.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();
答案 1 :(得分:1)
在我看来,目前的答案,包括已接受的答案,远比必要的复杂得多。如果你有一个可以在编译时使用的类型T
,你可以得到MethodInfo
,如下所示:
Func<IEnumerable<T>, Func<T, bool>, IEnumerable<T>> whereDelegate = Enumerable.Where;
MethodInfo whereMethodInfo = whereDelegate.Method;
作为额外奖励,这是强类型。如果Enumerable.Where
可以被解析,它将只编译 ,而不是寻找字符串"Where"
的任何东西:如果你不小心输入"Wehre"
,它就会很好地编译相反,但在运行时会失败。
答案 2 :(得分:0)
我认为分开两个重载的最简单方法是:
var whereMethod = typeof(Enumerable).GetMethods()
.Single(m => m.Name == "Where" && m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericType(typeof(TSub));
答案 3 :(得分:0)
模板类型为T,这应该有效:
var methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public | BindingFlags.Static, new Type[]{ typeof(IEnumerable<T>), typeof(Func<T, bool>) });
Where方法有两个参数:IEnumerable和比较函数。