引用所需的重载泛型方法

时间:2009-02-25 22:12:06

标签: c# reflection generics methodinfo

给出

public Class Example
{

public static void Foo< T>(int ID){}

public static void Foo< T,U>(int ID){}

}

问题:

  1. 将此称为“重载通用方法”是否正确?
  2. 如何在创建MethodInfo对象时指定任一方法?

    Type exampleType = Type.GetType("fullyqualifiednameOfExample, namespaceOfExample");
    MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null);
    
  3. 参数4导致编译器非常不满

6 个答案:

答案 0 :(得分:12)

我无法找到一种方法来使用GetMethod做你想做的事。但是你可以获得所有方法并浏览列表,直到找到你想要的方法。

请记住,在实际使用之前,您需要调用MakeGenericMethod。

var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
    mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
    MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
    Example example= new Example();
    closedMi.Invoke(example, new object[] { 5 });
}

答案 1 :(得分:3)

以下是您的问题的答案以及示例:

  1. 是的,虽然这里有两件事要注意泛型方法,类型推理和重载方法解析。类型推断在编译器尝试解析重载的方法签名之前的编译时发生。编译器将类型推断逻辑应用于共享相同名称的所有通用方法。在重载解析步骤中,编译器仅包括那些类型推断成功的泛型方法。 More here...

  2. 请参阅下面的完整示例控制台应用程序代码,该代码显示如何在创建MethodInfo对象时指定Foo方法的多个变体,然后使用Extension方法调用:

  3. Program.cs的

    class Program
    {
        static void Main(string[] args)
        {
            MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
                new[] { typeof(string) },
                new[] { typeof(int) },
                typeof(void));
    
            MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
                new[] { typeof(string), typeof(int) },
                new[] { typeof(int) },
                typeof(void));
    
            MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
                new[] { typeof(string) },
                new[] { typeof(string) },
                typeof(void));
    
            MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
                new[] { typeof(string), typeof(int) },
                new[] { typeof(int), typeof(string) },
                typeof(string));
    
            Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
            Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
            Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
            Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
        }
    }
    

    Example.cs:

    public class Example
    {
        public static void Foo<T>(int ID) { }
        public static void Foo<T, U>(int ID) { }
        public static void Foo<T>(string ID) { }
        public static string Foo<T, U>(int intID, string ID) { return ID; }
    }
    

    Extensions.cs:

    public static class Extensions
    {
        public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
        {
            MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                               where m.Name == name &&
                               m.GetGenericArguments().Length == genericArgTypes.Length &&
                               m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
                               m.ReturnType == returnType
                               select m).Single().MakeGenericMethod(genericArgTypes);
    
            return foo1;
        }
    }
    

答案 2 :(得分:1)

更好:

尝试获取System.Linq.Enumerable.Select

的正确重载的示例
    private static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
    {
        return ((MethodCallExpression)expression.Body).Method;
    }

    public static void CallSelect()
    {
        MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition();
        definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) });
    }

答案 3 :(得分:0)

这是您需要的Linq单线:

MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);

答案 4 :(得分:0)

我对你的lambda查询进行了一些修改。

当参数类型为si generic时,你必须这样做:

我添加pi.ParameterType.GetGenericTypeDefinition()

(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)

这样方法工作得很好

MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                         where m.Name == name
                         && m.GetGenericArguments().Length == genericArgTypes.Length
                         && m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
                         (returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
                         select m).FirstOrDefault();
      if (foo1 != null)
      {
        return foo1.MakeGenericMethod(genericArgTypes);
      }
      return null;

示例:

通过修改方法,我可以打电话 这种扩展方法

public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)

我的新帮手

var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>)); 

我的助手的签名是

   public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)

答案 5 :(得分:0)

找到所需的MethodInfo的另一个班轮是创建一个委托;

var methodInfo = new Action<int>(Example.Foo<object,object>).Method.GetGenericMethodDefinition();