C# 在参数为泛型的情况下,查找使用参数类型的方法

C# 在参数为泛型的情况下,查找使用参数类型的方法,c#,.net,reflection,C#,.net,Reflection,我肯定这是重复的,但我找不到答案 System.Linq.Queryable有一个具有以下签名的方法: public static int Count<TSource>( this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate); 你可以用 var method = typeof (System.Linq.Queryable).GetM

我肯定这是重复的,但我找不到答案

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

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

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==“选择”
&&a.MakeGenericMethod(typeof(object),typeof(object)).GetParameters()[1]。ParameterType==typeof(Expression));
var sel2=typeof(Queryable).GetMethods().Single(a=>a.Name==“选择”
&&a.MakeGenericMethod(typeof(object),typeof(object)).GetParameters()[1]。ParameterType==typeof(Expression));

最省力的方法可能是用表达式树捕获所需的方法,然后深入查找方法引用。您可以这样做一次以获取泛型方法定义,然后缓存结果并在必要时重用它

Expression<Func<IQueryable<int>, int>> getCount = p => p.Count();
MethodInfo countMethod = ((MethodCallExpression)getCount.Body).Method.GetGenericMethodDefinition();
表达式getCount=p=>p.Count(); MethodInfo countMethod=((MethodCallExpression)getCount.Body).Method.GetGenericMethodDefinition(); 这样做的好处是对API变化具有一定的弹性(例如,增加更多的“计数”成员);返回的方法将是表达式在编译时绑定到的任何方法

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

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;
}
public static MethodInfo MethodOf(Expression accessExpression,bool dropTypeArguments=false)
{
if(accessExpression==null)
抛出新ArgumentNullException(“accessExpression”);
var callExpression=accessExpression.Body作为MethodCallExpression;
if(callExpression==null)
抛出新ArgumentException(“表达式体必须是方法调用。”,“accessExpression”);
var method=callExpression.method;
if(dropTypeArguments&&method.IsGenericMethod)
返回方法。GetGenericMethodDefinition();
返回法;
}
公共静态MethodInfo MethodOf(表达式调用,bool dropTypeArguments=false)
{
if(call==null)
抛出新的ArgumentNullException(“调用”);
var callExpression=call.Body作为MethodCallExpression;
if(callExpression==null)
抛出新ArgumentException(“表达式体必须是方法调用。”,“调用”);
var method=callExpression.method;
if(dropTypeArguments&&method.IsGenericMethod)
返回方法。GetGenericMethodDefinition();
返回法;
}
第一个重载用于静态样式调用,后一个重载用于实例样式调用,例如:

var countMethod1 = Extensions.MethodOf(() => Queryable.Count(default(IQueryable<int>)), dropTypeArguments: true);
var countMethod2 = Extensions.MethodOf((IQueryable<int> p) => p.Count(), dropTypeArguments: true);
var countMethod1=Extensions.MethodOf(()=>Queryable.Count(默认值(IQueryable)),dropTypeArguments:true);
var countMethod2=Extensions.MethodOf((IQueryable p)=>p.Count(),dropTypeArguments:true);
要保留类型参数(例如,解析
Count()
而不是
Count()
),只需省略
dropTypeArguments:true
参数或将其设置为
false


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

在这种情况下我可以,但这不适用于Select(它有两个重载-每个重载两个参数)。如果您没有可查询类型,但有另一个泛型类型(不是泛型方法类型),则可以使用公共类MyGenType{public void Select(){}public void Select(T withGenPar){}public void Select(Expression Expression){}public static MethodInfo SecondSelect{get{return typeof(MyGenType).GetMethod(“Select”,new[]{typeof(T)};}}}}或var seconds=typeof(MyGenType).GetMethod(“Select”,new[]{typeof(int)});您是否确实知道使用.net API本身无法将GetMethod与精确的参数类型一起使用?一般来说,是的,但不适用于泛型方法。
GetMethod()
不会尝试绑定泛型类型参数。您需要使用类似于
GetMethods()
FindMember()的方法
并对结果进行迭代,检查参数和返回类型,直到找到匹配项。但正确地执行此操作很麻烦,简单的解决方案(请参见@pil0t的答案)很脆弱;但至少他使用
Single()的解决方案
在将来的版本中,如果方法变得不明确,将抛出。但是,我的解决方案将轻松、可靠地为您提供精确匹配。在我的情况下,类型在编译时是未知的。然后替换任何类型(我使用了
int
)并删除类型参数以获得泛型方法定义。当您知道运行时类型时,使用正确的类型调用
MakeGenericMethod()
,以绑定该方法。(我的答案中的所有示例都将为您提供
Count()的泛型定义)
无论您使用什么
IQueryable
实例化来解决它)
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);