C#动态调⽤泛型类、泛型⽅法
在制作⼀个批量序列化⼯具时遇到了如下问题,在此记录⼀下,仅供参考。
主程序加载另⼀个程序集,将其中的所有类取出,然后对这些类分别调⽤泛型类或泛型⽅法。控制台程序解决⽅案如下:Main⼯程:提供Worker类进⾏数据操作,XMLTool<T>泛型类将数据集序列化为.xml⽂档,RootCollection<T>类封装数据集Worker类
  提供成员⽅法void DoWork<T>()、List<T> GetList<T>()、静态成员⽅法StaticDoWork<T>(),代码如下:
1 public class Worker
2    {
3        public Worker()
4        {
5        }
6
7        public void DoWork<T>()
8        {
9            Type t = typeof(T);
10            Console.WriteLine("Get Class: {0}", t.Name);
11            PropertyInfo[] properties = t.GetProperties();
12            foreach (PropertyInfo property in properties)
13            {
14                Console.WriteLine("\tproperty.Name: " + property.Name + "\tproperty.MemberType: " + property.PropertyType);
15            }
16        }
17
18        public static void StaticDoWork<T>()
19        {
20            Type t = typeof(T);
21            Console.WriteLine("Get Class: {0}", t.Name);
22            PropertyInfo[] properties = t.GetProperties();
23            foreach (PropertyInfo property in properties)
24            {
25                Console.WriteLine("\tproperty.Name: " + property.Name + "\tproperty.MemberType: " + property.PropertyType);
26            }
27        }
28
29        public List<T> GetList<T>()
30        {
31            Console.WriteLine("Generate List for [{0}]", typeof(T).Name);
32            return new List<T>()
33            {
34                Activator.CreateInstance<T>(),
35                Activator.CreateInstance<T>()
36            };
37        }
38    }
XMLTool<T>类
1publicclass XMLTool<T>
2    {
3publicstaticvoid XmlSerialize_Save(List<T> needSerializedList, string xmlDirPath, string xmlFileName)
4        {
5            RootCollection<T> collection = new RootCollection<T>();
6            collection.ItemList = needSerializedList;
7if (!Directory.Exists(xmlDirPath))
8                Directory.CreateDirectory(xmlDirPath);
9using (System.IO.FileStream stream = new System.IO.FileStream(xmlFileName, System.IO.FileMode.Create))
10            {
11                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(collection.GetType());
12                serializer.Serialize(stream, collection);
13            }
14        }
15    }
RootCollection<T>类:
1    [Serializable]
2    public class RootCollection<T>
3    {
4        public RootCollection()
5        {
6            itemList = new List<T>();
7        }
8
9        private List<T> itemList;
10
11        public List<T> ItemList
12        {
13            get { return itemList; }
14            set { itemList = value; }
15        }
16    }
MockClassLib⼯程:提供BaseEntity、Apple、Cat和Person类
BaseEntity类:抽象类,负责初始化类成员
1    public abstract class BaseEntity
2    {
3        public BaseEntity()
4        {
5            InitiaWithNull();
6        }
7
8        private void InitiaWithNull()
9        {
10            Type type = this.GetType();
11            PropertyInfo[] properties = type.GetProperties();
12            string[] PropNames = new string[properties.Length];
13            Dictionary<string, PropertyInfo> PropNameToInfo = new Dictionary<string, PropertyInfo>();
14            for (int i = 0; i < properties.Length; i++)
15            {
16                PropNames[i] = properties[i].Name;
17                PropNameToInfo.Add(PropNames[i], properties[i]);
18            }
19
20            foreach (string propname in PropNames)
21            {
22                string proptype = PropNameToInfo[propname].PropertyType.Name;
23
24                object value = null;
25                if (NullValue.Keys.Contains(proptype))
26                    value = NullValue[proptype];
27
28                type.GetProperty(propname).SetValue(this, value, null);
29            }
30        }
31
32        private static readonly Dictionary<string, object> NullValue = new Dictionary<string, object>()
33            {
34                { "String", String.Empty },
35                { "DateTime", DateTime.MinValue},
36                { "Decimal", Decimal.MinValue}
37            };
38    }
Apple、Cat和Person类:测试类,继承于BaseEntity
1    public class Apple : BaseEntity
2    {
3        public string Color { get; set; }
4    }
5
6    public class Cat : BaseEntity
7    {
8        public string Type { get; set; }
9    }
10
11    public class Person : BaseEntity
12    {
13        public int ID { get; set; }
14        public string Name { get; set; }
15    }
Main⼯程的Program的Main⽅法中,⼀般情况下,调⽤Worker的泛型⽅法来处理测试类的话,可以写为:
Worker worker = new Worker();
worker.DoWork<Apple>();
worker.DoWork<Cat>();
worker.DoWork<Person>();
但是,如果MockClassLib中需要处理的类型⾮常多时,这样显⽰调⽤必然是不灵活的,应当怎样向泛型⽅法DoWork<T>()的尖括号中动态传⼊类型呢?
考虑代码:
//Load assembly
Assembly mockAssembly = Assembly.LoadFrom("MockClassLibrary.dll");
Type[] typeArray = mockAssembly.GetTypes();
//Create instance of Worker
Worker worker = new Worker();
foreach(Type curType in typeArray)
{
worker.DoWork<curType>();  //Error
}
可以看到,Type类型的实例是⽆法直接传⼊泛型⽅法的尖括号中的,T要求显式指明类型名。
下⾯通过反射⽅式来获取泛型⽅法,并创建特定类型的泛型⽅法。
对于⾮静态⽅法:public void DoWork<T>()
对于⾮静态⽅法,调⽤MethodInfo.Invoke(object, object[])时,第⼀个参数需要指明泛型⽅法的所有者(即这⾥创建的worker对象),第⼆个参数为泛
型⽅法的参数列表,DoWork<T>()没有输⼊参数,所以设为null
//Create an instance of Worker
Worker worker = new Worker();
//Get type of Worker
Type workerType = typeof(Worker);
//Get Generic Method
MethodInfo doWorkMethod = workerType.GetMethod("DoWork");
//Invoke DoWork<T> with different Type
foreach (Type curType in typeArray)
{
if (curType.IsClass && !curType.IsAbstract)//Filter BaseEntity
{
MethodInfo curMethod = doWorkMethod.MakeGenericMethod(curType);
curMethod.Invoke(worker, null);//Member method,use instance
}
}
对于静态⽅法:public static void StaticDoWork<T>()
不同于⾮静态⽅法,这⾥直接反射的类静态⽅法,所以Invoke()的第⼀个参数设为null
//Get type of Worker
Worker worker = new Worker();
//Get Generic Method
MethodInfo staticDoWorkMethod = workerType.GetMethod("StaticDoWork");
//Invoke StaticDoWork<T>
foreach (Type curType in typeArray)
{
getsavefilename
if (curType.IsClass && !curType.IsAbstract)
{
MethodInfo curMethod = staticDoWorkMethod.MakeGenericMethod(curType);
curMethod.Invoke(null, null);//Static method
}
}
对于有返回值的⾮静态⽅法:public List<T> GetList()
如同动态调⽤DoWork<T>()⽅法⼀样,只是在处理返回值时,可以使⽤下⾯的⽅法
1 IList tempList = (IList)curMethod.Invoke(worker, null);
2 //Or
3 IEnumerable tempList = (IEnumerable)curMethod.Invoke(worker, null);
对于泛型类:XMLTool<T>
下⾯要使⽤泛型类XMLTool<T>的静态⽅法public static void XmlSerialize_Save(List<T> list, string dirPath, string fileName)⽅法。
⾸先应通过反射构造出指定类型的泛型类XMLTool<T>,再反射出其中的XmlSerialize_Save⽅法并使⽤。
1 //Use Generic Class
2 Type xmlToolType = typeof(XMLTool<>).MakeGenericType(curType);
3
4 //Get method
5 MethodInfo saveMethod = xmlToolType.GetMethod("XmlSerialize_Save");
6
7 //Invoke
8 saveMethod.Invoke
9 (
10    null, //Static method
11    new object[] { resultList, @"c:\", @"c:\Test_" + curType.Name + ".xml" }
12 );
Program-->Main()⽅法的全部代码:
1 namespace RetrieveUnknownClass
2 {
3    class Program
4    {
5        static void Main(string[] args)
6        {
7            //Load assembly
8            Assembly mockAssembly = Assembly.LoadFrom("MockClassLibrary.dll");
9            Type[] typeArray = mockAssembly.GetTypes();
10
11            //Create instance of Worker
12            Type workerType = typeof(Worker);
13            Worker worker = new Worker();
14
15            #region Member method
16
17            Console.WriteLine(">>>>>>>>>Use Generic Method:");
18            MethodInfo doWorkMethod = workerType.GetMethod("DoWork");
19
20            //Invoke DoWork<T>
21            foreach (Type curType in typeArray)
22            {
23                if (curType.IsClass && !curType.IsAbstract)
24                {
25                    MethodInfo curMethod = doWorkMethod.MakeGenericMethod(curType);
26                    curMethod.Invoke(worker, null);//Member method,use instance
27                }
28            }
29
30            #endregion
31
32            #region Static method
33
34            Console.WriteLine("\r\n>>>>>>>>>Use Static Generic Method:");
35            MethodInfo staticDoWorkMethod = workerType.GetMethod("StaticDoWork");
36
37            //Invoke StaticDoWork<T>
38            foreach (Type curType in typeArray)
39            {
40                if (curType.IsClass && !curType.IsAbstract)
41                {
42                    MethodInfo curMethod = staticDoWorkMethod.MakeGenericMethod(curType);
43                    curMethod.Invoke(null, null);//Static method
44                }
45            }
46
47            #endregion
48
49            #region Get A List & Serialize It to Xml File With Generic
50
51            Console.WriteLine("\r\n>>>>>>>>>Get List By Generic Method:");
52            MethodInfo getListMethod = workerType.GetMethod("GetList");
53
54            foreach (Type curType in typeArray)
55            {
56                if (curType.IsClass && !curType.IsAbstract)
57                {
58                    MethodInfo curMethod = getListMethod.MakeGenericMethod(curType);
59                    //Generate List
60                    IList resultList = (IList)curMethod.Invoke(worker, null);
61                    //Show List
62                    ShowList(resultList);
63                    //Use Generic Class
64                    Type xmlToolType = typeof(XMLTool<>).MakeGenericType(curType);
65                    MethodInfo saveMethod = xmlToolType.GetMethod("XmlSerialize_Save");
66
67                    saveMethod.Invoke
68                        (
69                            null, //Static method
70                            new object[] { resultList, @"c:\", @"c:\Test_" + curType.Name + ".xml" }
71                        );
72                }
73            }
74
75            Console.WriteLine("\r\n");
76            #endregion
77        }
78
79        public static void ShowList(IList list)
80        {
81            Console.WriteLine("Type of list: {0}\r\nCount of current list: {1}\r\nType of item in list: {2}\r\n",
82                list.GetType(),
83                list.Count,
84                list[0].GetType());
85        }
86    }
87 }

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。