问题
I am trying to get return the correct "Where" extension method using reflection, in order to build a custom Expression. I have tried several ways but the closest I get, throws an exception: "An unhandled exception of type 'System.Reflection.AmbiguousMatchException' occurred in mscorlib.dll"
I know this is because there are two Where methods defined in the Enumrable class - but how can I return the Where method which using only just a predicate of
Func<T, bool>.
What I have at the moment is:
var collectionType = typeof(TSub);
Type tIEnumerable = typeof(IEnumerable<>).MakeGenericType(collectionType);
MethodInfo methodInfo =
typeof(Enumerable)
.GetMethod("Where")
.MakeGenericMethod(collectionType);
I have also tried (this one returns null):
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { typeof(TSub )});
and (also returns null)
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", new[] { collectionType })
and (this one returns the same Ambiguous Exception)
MethodInfo methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public | BindingFlags.Static)
Could anyone help at all please?
Thanks
回答1:
In my opinion, the current answers, including the accepted one, are far more complicated than necessary. If you have a type T
that you can use at compile time, you can get the MethodInfo
like so:
Func<IEnumerable<T>, Func<T, bool>, IEnumerable<T>> whereDelegate = Enumerable.Where;
MethodInfo whereMethodInfo = whereDelegate.Method;
As an extra bonus, this is strongly typed. It will compile only if the Enumerable.Where
can be resolved, as opposed to anything that looks for a string "Where"
: that would compile just fine if you accidentally type "Wehre"
instead, but would fail at runtime.
回答2:
I'm sure there are easier ways, but here's one:
typeof(Enumerable).GetMethods()
.Single(method => method.Name == "Where"
&& method.GetParameters()
.ElementAt(1)
.ParameterType
.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericMethod(typeof(TSub))
This is a little brittle though (think Microsoft adding more overloads in a future version of .NET). Perhaps more robust (but even more monstrous; surely there must be a better way) is:
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();
回答3:
Having a template type T, this should work:
var methodWhere = typeof(Enumerable).GetMethod("Where", BindingFlags.Public | BindingFlags.Static, new Type[]{ typeof(IEnumerable<T>), typeof(Func<T, bool>) });
The Where method takes two parameters: the IEnumerable and the comparison function.
回答4:
I think the easiest way to tell the two overloads apart is:
var whereMethod = typeof(Enumerable).GetMethods()
.Single(m => m.Name == "Where" && m.GetParameters()[1].ParameterType.GetGenericTypeDefinition() == typeof(Func<,>))
.MakeGenericType(typeof(TSub));
来源:https://stackoverflow.com/questions/22117113/how-to-get-the-correct-methodinfo-for-where-extension-method