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)
{
getsavefilenameif (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小时内删除。
发表评论