I have IQueryable< T> source and i want to dynamically call IQueryable< T>.Count().
So, i need MethodInfo of Count method declared in IQueryable.
this is its signature (in IQueryable<>) from msdn:
public static int Count<TSource>(
this IQueryable<TSource> source
)
This is how far i got:
Expression expr; //this is expression which holds my IQueryable<T>
MethodInfo mi = expr.Type.GetMethod("Count", BindingFlags.Static | BindingFlags.Public, null, new[] { expr.Type }, null);
but my mi is always null;
I also tried:
mi = typeof(IQueryable<>).GetMethod("Count", BindingFlags.Static | BindingFlags.Public, null, new[] { expr.Type }, null);
but again null.
My final goal would be:
Expression.Call(mi, expr);
UPDATE: this is how I get Sum Extension method:
MethodInfo sum = typeof(Queryable).GetMethod("Sum", BindingFlags.Static | BindingFlags.Public, null, new[] { typeof(IQueryable<decimal>) }, null);
and this works, but this Sum method is not generic. It is though static.
You need to crack out the generic argument of the IQueryable<T>
type and use that; also the type that owns the method is not IQueryable<T>
, it is Queryable
- if you think about it - interfaces can't have static methods (well, as a commenter has pointed out, in C# that is) :).
Also, because it's a generic method you can't match the parameters in the way you've tried: because you need to pass the generic type definition IQuerable<TSource>
- not a generic type IQueryable<int>
or whatever the actual expression is.
Instead you can just look for a single-parametered version of a static method called 'Count' on the Queryable
type:
Type genericArgument = expr.GetGenericArguments()[0];
MethodInfo countMethod = typeof(Queryable)
.GetMethods(BindingFlags.Static | BindingFlags.Public)
//narrow the search before doing 'Single()'
.Single(mi => mi.Name == "Count"
// this check technically not required, but more future proof
&& mi.IsGenericMethodDefinition
&& mi.GetParameters().Length == 1)
.MakeGenericMethod(genericArgument);
//now you can bind to 'countMethod'
Update 7th March 2017 - Clearly, something changed in the framework which stopped the original version of the code example from working - this is an updated version which should work
Going into it a bit further - the signature of the method is:
public static int Count<TSource>(
this IQueryable<TSource> source
)
So while the parameter type is IQueryable<TSource>
it's generic over the TSource
type - hence the reason why you need to fish into your IQueryable<TSource>
expression and grab it's generic argument. And you should also be able to see what I mean about the parameter here.
Let the compiler get the method for you.
Type genericArgument = expr.GetGenericArguments()[0];
var fakeExp = (Expression<Func<IQueryable<int>, int>>)(q => q.Count());
var mi = ((MethodCallExpression)fakeExp.Body).Method.GetGenericMethodDefinition().MakeGenericMethod(genericArgument);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With