Reputation: 21750
I am sure this is a duplicate, but I can not find the answer.
System.Linq.Queryable
has a method with following signature:
public static int Count<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, bool>> predicate);
How do I use System.Type::GetMethod
method to get this method?
typeof(System.Linq.Queryable).GetMethod("Count", type[]{ ??? });
Upvotes: 2
Views: 405
Reputation: 25623
The method with the least effort would probably be to capture the method you want with an expression tree, then delve in to find the method reference. You can do this once to get the generic method definition, then cache the result and reuse it as necessary.
Expression<Func<IQueryable<int>, int>> getCount = p => p.Count();
MethodInfo countMethod = ((MethodCallExpression)getCount.Body).Method.GetGenericMethodDefinition();
This has the benefit of being somewhat resilient to API changes (e.g., the addition of more "Count" members); the method returned will be whatever method your expression binds to at compile time.
You could extract this behavior out into utility methods if you like:
public static MethodInfo MethodOf(Expression<Action> accessExpression, bool dropTypeArguments = false)
{
if (accessExpression == null)
throw new ArgumentNullException("accessExpression");
var callExpression = accessExpression.Body as MethodCallExpression;
if (callExpression == null)
throw new ArgumentException("Expression body must be a method call.", "accessExpression");
var method = callExpression.Method;
if (dropTypeArguments && method.IsGenericMethod)
return method.GetGenericMethodDefinition();
return method;
}
public static MethodInfo MethodOf<TInstance>(Expression<Action<TInstance>> call, bool dropTypeArguments = false)
{
if (call == null)
throw new ArgumentNullException("call");
var callExpression = call.Body as MethodCallExpression;
if (callExpression == null)
throw new ArgumentException("Expression body must be a method call.", "call");
var method = callExpression.Method;
if (dropTypeArguments && method.IsGenericMethod)
return method.GetGenericMethodDefinition();
return method;
}
Use the first overload for static-style invocations and the latter for instance-style invocations, e.g.:
var countMethod1 = Extensions.MethodOf(() => Queryable.Count(default(IQueryable<int>)), dropTypeArguments: true);
var countMethod2 = Extensions.MethodOf((IQueryable<int> p) => p.Count(), dropTypeArguments: true);
To preserve the type arguments (e.g., to resolve Count<int>()
instead of Count<T>()
) just omit the dropTypeArguments: true
argument or set it to false
.
Note that these aren't terribly comprehensive; they will not, for example, drop generic parameters on the declaring type (only on the method itself). Feel free to use, extend, or throw away :).
Upvotes: 1
Reputation: 2183
You could use
var method = typeof (System.Linq.Queryable).GetMethods().Single(a=>a.Name == "Count" && a.GetParameters().Length == 2);
And after, if you want to invoke it
method.MakeGenericMethod(typeof (YourType));
For additional, it could be filtered (for different selects):
var sel1 = typeof (Queryable).GetMethods().Single(a => a.Name == "Select"
&& a.MakeGenericMethod(typeof(object), typeof(object)).GetParameters()[1].ParameterType == typeof(Expression<Func<object, object>>));
var sel2 = typeof(Queryable).GetMethods().Single(a => a.Name == "Select"
&& a.MakeGenericMethod(typeof(object), typeof(object)).GetParameters()[1].ParameterType == typeof(Expression<Func<object,int, object>>));
Upvotes: 1