使用参数类型查找参数为泛型的方法

本文关键字:参数 泛型 方法 查找 类型 | 更新日期: 2023-09-27 18:37:14

我确定这是一个重复的,但我找不到答案。

System.Linq.Queryable有一个具有以下签名的方法:

public static int Count<TSource>(
    this IQueryable<TSource> source, 
    Expression<Func<TSource, bool>> predicate);

如何使用System.Type::GetMethod方法来获取此方法?

typeof(System.Linq.Queryable).GetMethod("Count", type[]{ ??? });

使用参数类型查找参数为泛型的方法

您可以使用

var method = typeof (System.Linq.Queryable).GetMethods().Single(a=>a.Name == "Count" && a.GetParameters().Length == 2);

之后,如果你想调用它

method.MakeGenericMethod(typeof (YourType));

对于其他,可以对其进行过滤(针对不同的选择):

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>>));

最省力的方法可能是使用表达式树捕获所需的方法,然后深入研究以查找方法引用。 您可以执行此操作一次以获取泛型方法定义,然后缓存结果并根据需要重用它。

Expression<Func<IQueryable<int>, int>> getCount = p => p.Count();
MethodInfo countMethod = ((MethodCallExpression)getCount.Body).Method.GetGenericMethodDefinition();

这样做的好处是对 API 更改有一定的弹性(例如,添加更多的"Count"成员);返回的方法将是表达式在编译时绑定到的任何方法。

如果您愿意,可以将此行为提取到实用程序方法中:

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;
}

将第一个重载用于静态样式调用,将后者用于实例样式调用,例如:

var countMethod1 = Extensions.MethodOf(() => Queryable.Count(default(IQueryable<int>)), dropTypeArguments: true);
var countMethod2 = Extensions.MethodOf((IQueryable<int> p) => p.Count(), dropTypeArguments: true);

要保留类型参数(例如,解析Count<int>()而不是Count<T>()),只需省略dropTypeArguments: true参数或将其设置为 false

请注意,这些不是很全面;例如,它们不会在声明类型上删除泛型参数(仅在方法本身上)。 随意使用、扩展或丢弃:)。