选择具有反射的右通用方法

选择具有反射的右通用方法

我想通过反射选择正确的通用方法,然后调用它。

通常这很容易。例如

var method = typeof(MyType).GetMethod("TheMethod");var typedMethod = method.MakeGenericMethod(theTypeToInstantiate);

但是,当方法存在不同的泛型重载时,问题就开始了。例如,System.Linq.Queryable类中的静态方法。'Where'方法有两种定义

static IQueryable<T> Where(this IQueryable<T> source, Expression<Func<T,bool>> predicate)static IQueryable<T> Where(this IQueryable<T> source, Expression<Func<T,int,bool>> predicate)

这说明GetMethod无法正常工作,因为它无法让两者黯然失色。因此,我想选择正确的。

到目前为止,我经常只采取第一种或第二种方法,这取决于我的需要。像这样:

var method = typeof (Queryable).GetMethods().First(m => m.Name == "Where");var typedMethod = method.MakeGenericMethod(theTypeToInstantiate);

但是我对此并不满意,因为我做了一个很大的假设,即第一种方法是正确的。我宁愿通过参数类型找到正确的方法。但我无法弄清楚如何。

我尝试传递'类型',但它没有用。

        var method = typeof (Queryable).GetMethod(
            "Where", BindingFlags.Static,
            null,
            new Type[] {typeof (IQueryable<T>), typeof (Expression<Func<T, bool>>)},
            null);

所以有人知道如何通过反射找到'正确'的通用方法。例如,Queryable类的'Where'方法的正确版本?


墨色风雨
浏览 391回答 3
3回答

白衣染霜花

它可以做到,但它不漂亮!例如,要获得Where问题中提到的第一个重载,您可以这样做:var&nbsp;where1&nbsp;=&nbsp;typeof(Queryable).GetMethods() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.Name&nbsp;==&nbsp;"Where") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;new&nbsp;{&nbsp;M&nbsp;=&nbsp;x,&nbsp;P&nbsp;=&nbsp;x.GetParameters()&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.P.Length&nbsp;==&nbsp;2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[0].ParameterType.IsGenericType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[0].ParameterType.GetGenericTypeDefinition()&nbsp;==&nbsp;typeof(IQueryable<>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[1].ParameterType.IsGenericType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[1].ParameterType.GetGenericTypeDefinition()&nbsp;==&nbsp;typeof(Expression<>)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;new&nbsp;{&nbsp;x.M,&nbsp;A&nbsp;=&nbsp;x.P[1].ParameterType.GetGenericArguments()&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.A[0].IsGenericType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.A[0].GetGenericTypeDefinition()&nbsp;==&nbsp;typeof(Func<,>)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;new&nbsp;{&nbsp;x.M,&nbsp;A&nbsp;=&nbsp;x.A[0].GetGenericArguments()&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.A[0].IsGenericParameter &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.A[1]&nbsp;==&nbsp;typeof(bool)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;x.M) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.SingleOrDefault();或者如果你想要第二次重载:var&nbsp;where2&nbsp;=&nbsp;typeof(Queryable).GetMethods() &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.Name&nbsp;==&nbsp;"Where") &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;new&nbsp;{&nbsp;M&nbsp;=&nbsp;x,&nbsp;P&nbsp;=&nbsp;x.GetParameters()&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.P.Length&nbsp;==&nbsp;2 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[0].ParameterType.IsGenericType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[0].ParameterType.GetGenericTypeDefinition()&nbsp;==&nbsp;typeof(IQueryable<>) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[1].ParameterType.IsGenericType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.P[1].ParameterType.GetGenericTypeDefinition()&nbsp;==&nbsp;typeof(Expression<>)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;new&nbsp;{&nbsp;x.M,&nbsp;A&nbsp;=&nbsp;x.P[1].ParameterType.GetGenericArguments()&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.A[0].IsGenericType &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.A[0].GetGenericTypeDefinition()&nbsp;==&nbsp;typeof(Func<,,>)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;new&nbsp;{&nbsp;x.M,&nbsp;A&nbsp;=&nbsp;x.A[0].GetGenericArguments()&nbsp;}) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Where(x&nbsp;=>&nbsp;x.A[0].IsGenericParameter &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.A[1]&nbsp;==&nbsp;typeof(int) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&&&nbsp;x.A[2]&nbsp;==&nbsp;typeof(bool)) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.Select(x&nbsp;=>&nbsp;x.M) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.SingleOrDefault();

慕田峪4524236

您可以在编译时优雅地选择方法的特定泛型重载,而不将任何字符串传递给运行时搜索,就像这里的其他答案一样。静态方法假设您有多个同名的静态方法,例如:public&nbsp;static&nbsp;void&nbsp;DoSomething<TModel>(TModel&nbsp;model)public&nbsp;static&nbsp;void&nbsp;DoSomething<TViewModel,&nbsp;TModel>(TViewModel&nbsp;viewModel,&nbsp;TModel&nbsp;model)//&nbsp;etc如果您创建的Action或Func与您要查找的重载的泛型计数和参数计数相匹配,则可以在编译时使用相对较少的杂技来选择它。示例:选择第一个方法 - 返回void,因此使用Action,取一个泛型。我们使用object来避免指定类型:var&nbsp;method&nbsp;=&nbsp;new&nbsp;Action<object>(MyClass.DoSomething<object>);示例:选择第二个方法 - 返回void,因此Action,2个泛型类型因此使用type对象两次,对于2个通用参数中的每一个使用一次:var&nbsp;method&nbsp;=&nbsp;new&nbsp;Action<object,&nbsp;object>(MyClass.DoSomething<object,&nbsp;object>);你只需要你想要的方法,而不需要做任何疯狂的管道,也不需要运行时搜索或使用有风险的字符串。MethodInfo的通常在Reflection中,您需要MethodInfo对象,您也可以以编译安全的方式获取该对象。这是当您传递要在方法中使用的实际泛型类型时。假设您想要上面的第二种方法:var&nbsp;methodInfo&nbsp;=&nbsp;method.Method.MakeGenericMethod(type1,&nbsp;type2);你的泛型方法没有任何反射搜索或调用GetMethod()或脆弱的字符串。静态扩展方法你引用Queryable.Where重载的具体例子迫使你在Func定义中有点花哨,但通常遵循相同的模式。最常用的Where()扩展方法的签名是:public&nbsp;static&nbsp;IQueryable<TModel>&nbsp;Where<TModel>(this&nbsp;IQueryable<TModel>,&nbsp;Expression<Func<TModel,&nbsp;bool>>)显然这会稍微复杂一点 - 这里是:var&nbsp;method&nbsp;=&nbsp;new&nbsp;Func<IQueryable<object>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Expression<Func<object,&nbsp;bool>>, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IQueryable<object>>(Queryable.Where<object>);var&nbsp;methodInfo&nbsp;=&nbsp;method.Method.MakeGenericMethod(modelType);实例方法结合Valerie的评论 - 要获得实例方法,您需要做一些非常相似的事情。假设您的类中有此实例方法:public&nbsp;void&nbsp;MyMethod<T1>(T1&nbsp;thing)首先选择与静态相同的方法:var&nbsp;method&nbsp;=&nbsp;new&nbsp;Action<object>(MyMethod<object>);然后调用GetGenericMethodDefinition()以获取泛型MethodInfo,最后传递您的类型MakeGenericMethod():var&nbsp;methodInfo&nbsp;=&nbsp;method.Method.GetGenericMethodDefinition().MakeGenericMethod(type1);解耦MethodInfo和参数类型在问题中没有要求这样做,但是一旦你做了上述事情,你可能会发现自己在一个地方选择了这个方法,并决定在另一个地方传递它的类型。你可以解开这两个步骤。如果您不确定要传入的泛型类型参数,则始终可以在不使用它们的情况下获取MethodInfo对象。静态的:var&nbsp;methodInfo&nbsp;=&nbsp;method.Method;例如:var&nbsp;methodInfo&nbsp;=&nbsp;method.Method.GetGenericMethodDefinition();并将其传递给其他一些知道它想要实例化的类型的方法并调用方法 - 例如:processCollection(methodInfo,&nbsp;type2);...protected&nbsp;void&nbsp;processCollection(MethodInfo&nbsp;method,&nbsp;Type&nbsp;type2){ &nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;type1&nbsp;=&nbsp;typeof(MyDataClass); &nbsp;&nbsp;&nbsp;&nbsp;object&nbsp;output&nbsp;=&nbsp;method.MakeGenericMethod(type1,&nbsp;type2).Invoke(null,&nbsp;new&nbsp;object[]&nbsp;{&nbsp;collection&nbsp;});}这特别有用的一件事是从类内部选择一个类的特定实例方法,然后将其暴露给以后需要它的各种类型的外部调用者。编辑:清理解释,合并了Valerie的实例方法示例。
打开App,查看更多内容
随时随地看视频慕课网APP