例如存在下列代碼:
1 2 3 4 5 6 7 8 9 10 | |
那麼在其他類下隻需要 using ExtensionMethods;,所有 string 類型的對象就都擁有了 zzyhost() 這個方法,而無需你重寫一個 string 類,比如:
|
像題主這段代碼就是使得 Bitmap 這個類型多了一個 function() 方法。
C#動态調用泛型類、泛型方法
在制作一個批量序列化工具時遇到了如下問題,在此記錄一下,僅供參考。
主程式加載另一個程式集,将其中的所有類取出,然後對這些類分别調用泛型類或泛型方法。控制台程式解決方案如下:
- Main工程:提供Worker類進行資料操作,XMLTool<T>泛型類将資料集序列化為.xml文檔,RootCollection<T>類封裝資料集
- Worker類
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 }
- BaseEntity類:抽象類,負責初始化類成員
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
}
}
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsISPrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdsATOfd3bkFGazxCMx8VesATMfhHLlN3XnxCMwEzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-YWan5SO3cTYiRWZhRmY5gDZ0EzMiN2YihTO0EWO2IWYkFDOk9CX1IzLcRDMxIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjL3M3Lc9CX6MHc0RHaiojIsJye.gif)
- 對于靜态方法: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)
{
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("Serialization Completed...\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 }
-
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 }
-
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 }
-
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 }
-
-
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 }
-
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 }
-
//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
}
//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
}
}
//Get type of Worker
Worker worker = new Worker();
//Get Generic Method
MethodInfo staticDoWorkMethod = workerType.GetMethod("StaticDoWork");
//Invoke StaticDoWork<T>
foreach (Type curType in typeArray)
{
if (curType.IsClass && !curType.IsAbstract)
{
MethodInfo curMethod = staticDoWorkMethod.MakeGenericMethod(curType);
curMethod.Invoke(null, null);//Static method
}
}
1 IList tempList = (IList)curMethod.Invoke(worker, null);
2 //Or
3 IEnumerable tempList = (IEnumerable)curMethod.Invoke(worker, null);
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 );
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("Serialization Completed...\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 }