如何通过反射调用普通类中的泛型方法?(有重载)

时间:2021-09-10 17:35:00
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace 复习
{
    class Program
    {
        static void Main(string[] args)
        {   
            Type t1 = typeof(Person);
            MethodInfo mi1 = t1.GetMethod("SayHello", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { }, null);
            MethodInfo mi2 = t1.GetMethod("SayHello", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(String) }, null);
            MethodInfo mi3 = t1.GetMethod("SayHello", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(String), typeof(Int32) }, null);
            
            //如何分别反射以下三个方法?
            //private void SayHello<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
            //private void SayHello<T1>(T1 t)
            //private void GM1<T1>(T1 t)

            object obj1 = Activator.CreateInstance(t1);
            //开始调用
            //
            Console.ReadKey();        
        }
    }
    class Person
    {
        private void SayHello()
        {
            Console.WriteLine("我是一个无参的方法");
        }
        private void SayHello(string s)
        {
            Console.WriteLine("我是一个有参的方法,参数:{0}", s);
        }
        private void SayHello(string s, int i)
        {
            Console.WriteLine("我是一个有两个参数的方法,参数:{0}、{1}", s, i);
        }
        private void SayHello<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
        {
            Console.WriteLine(t1.ToString() + t2.ToString() + t3.ToString());
        }
        private void SayHello<T1>(T1 t)
        {
            Console.WriteLine(t.ToString());
        }
        private void GM1<T1>(T1 t)
        {
            Console.WriteLine(t.ToString());
        }
    }
}

7 个解决方案

#2


以下是调用 PM1 的示例:
Person p = new Person();
Type t = p.GetType();
MethodInfo mi = t.GetMethod("GM1", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { typeof(string) });
mi2.Invoke(p, new object[] { "abcdefg" });

#4


markmark

#5


标个记号回头来看

#6


C#类成员分Field、Property和Method三种,Field通过名称就可以直接通过反射获取,后两种需要加上参数类型才能唯一确定,以Method为例,不同方法名称相同而参数不同是允许的(重载),但反射时就比较麻烦了。
    class Program
    {
        static void Main(string[] args)
        {
            Type t1 = typeof(Person);
            MethodInfo mi1 = GetMethod(t1, "SayHello");
            MethodInfo mi2 = GetMethod(t1, "SayHello", typeof(string));
            MethodInfo mi3 = GetMethod(t1, "SayHello", typeof(int));

            //如何分别反射以下三个方法?
            //private void SayHello<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
            MethodInfo mi4 = GetGenericMethod(t1, "SayHello", typeof(string), typeof(string), typeof(int));
            //private void SayHello<T1>(T1 t)
            MethodInfo mi5 = GetGenericMethod(t1, "SayHello", typeof(string));
            //private void GM1<T1>(T1 t)
            MethodInfo mi6 = GetGenericMethod(t1, "GM1", typeof(string));
        }

        static MethodInfo GetMethod(Type type, string name, params Type[] types)
        {
            return type.GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, types, null);
        }

        static MethodInfo GetGenericMethod(Type type, string name, params Type[] types)
        {
            foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            {
                if (mi.Name != name) continue;
                if (!mi.IsGenericMethod) continue;
                if (mi.GetGenericArguments().Length != types.Length) continue;

                return mi.MakeGenericMethod(types);
            }

            throw new MissingMethodException();
        }
    }
    class Person
    {
        private void SayHello()
        {
            Console.WriteLine("我是一个无参的方法");
        }
        private void SayHello(string s)
        {
            Console.WriteLine("我是一个有参的方法,参数:{0}", s);
        }
        private void SayHello(string s, int i)
        {
            Console.WriteLine("我是一个有两个参数的方法,参数:{0}、{1}", s, i);
        }
        private void SayHello<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
        {
            Console.WriteLine(t1.ToString() + t2.ToString() + t3.ToString());
        }
        private void SayHello<T1>(T1 t)
        {
            Console.WriteLine(t.ToString());
        }
        private void GM1<T1>(T1 t)
        {
            Console.WriteLine(t.ToString());
        }
    }

这里没考虑泛型方法带非泛型参数的情况,如果需要可自己琢磨。

#7


也许可以利用 dynamic 的语法糖?

dynamic d = obj1 as dynamic;
d.SayHello<int, double, string>(0, 1.0, "str");

#1


#2


以下是调用 PM1 的示例:
Person p = new Person();
Type t = p.GetType();
MethodInfo mi = t.GetMethod("GM1", BindingFlags.NonPublic | BindingFlags.Instance);
MethodInfo mi2 = mi.MakeGenericMethod(new Type[] { typeof(string) });
mi2.Invoke(p, new object[] { "abcdefg" });

#3


#4


markmark

#5


标个记号回头来看

#6


C#类成员分Field、Property和Method三种,Field通过名称就可以直接通过反射获取,后两种需要加上参数类型才能唯一确定,以Method为例,不同方法名称相同而参数不同是允许的(重载),但反射时就比较麻烦了。
    class Program
    {
        static void Main(string[] args)
        {
            Type t1 = typeof(Person);
            MethodInfo mi1 = GetMethod(t1, "SayHello");
            MethodInfo mi2 = GetMethod(t1, "SayHello", typeof(string));
            MethodInfo mi3 = GetMethod(t1, "SayHello", typeof(int));

            //如何分别反射以下三个方法?
            //private void SayHello<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
            MethodInfo mi4 = GetGenericMethod(t1, "SayHello", typeof(string), typeof(string), typeof(int));
            //private void SayHello<T1>(T1 t)
            MethodInfo mi5 = GetGenericMethod(t1, "SayHello", typeof(string));
            //private void GM1<T1>(T1 t)
            MethodInfo mi6 = GetGenericMethod(t1, "GM1", typeof(string));
        }

        static MethodInfo GetMethod(Type type, string name, params Type[] types)
        {
            return type.GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, types, null);
        }

        static MethodInfo GetGenericMethod(Type type, string name, params Type[] types)
        {
            foreach (MethodInfo mi in type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
            {
                if (mi.Name != name) continue;
                if (!mi.IsGenericMethod) continue;
                if (mi.GetGenericArguments().Length != types.Length) continue;

                return mi.MakeGenericMethod(types);
            }

            throw new MissingMethodException();
        }
    }
    class Person
    {
        private void SayHello()
        {
            Console.WriteLine("我是一个无参的方法");
        }
        private void SayHello(string s)
        {
            Console.WriteLine("我是一个有参的方法,参数:{0}", s);
        }
        private void SayHello(string s, int i)
        {
            Console.WriteLine("我是一个有两个参数的方法,参数:{0}、{1}", s, i);
        }
        private void SayHello<T1, T2, T3>(T1 t1, T2 t2, T3 t3)
        {
            Console.WriteLine(t1.ToString() + t2.ToString() + t3.ToString());
        }
        private void SayHello<T1>(T1 t)
        {
            Console.WriteLine(t.ToString());
        }
        private void GM1<T1>(T1 t)
        {
            Console.WriteLine(t.ToString());
        }
    }

这里没考虑泛型方法带非泛型参数的情况,如果需要可自己琢磨。

#7


也许可以利用 dynamic 的语法糖?

dynamic d = obj1 as dynamic;
d.SayHello<int, double, string>(0, 1.0, "str");