博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#动态调用泛型类、泛型方法
阅读量:5971 次
发布时间:2019-06-19

本文共 11081 字,大约阅读时间需要 36 分钟。

在制作一个批量序列化工具时遇到了如下问题,在此记录一下,仅供参考。

      主程序加载另一个程序集,将其中的所有类取出,然后对这些类分别调用泛型类或泛型方法。控制台程序解决方案如下:

  • 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
    () 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
    () 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
    GetList
    () 30 {
    31 Console.WriteLine("Generate List for [{0}]", typeof(T).Name); 32 return new List
    () 33 { 34 Activator.CreateInstance
    (), 35 Activator.CreateInstance
    () 36 }; 37 } 38 }

     

    • XMLTool<T>类
      1publicclass XMLTool
      2 {
      3publicstaticvoid XmlSerialize_Save(List
      needSerializedList, string xmlDirPath, string xmlFileName) 4 {
      5 RootCollection
      collection = new RootCollection
      (); 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
      3 {
      4 public RootCollection() 5 {
      6 itemList = new List
      (); 7 } 8 9 private List
      itemList; 10 11 public List
      ItemList 12 {
      13 get { return itemList; } 14 set { itemList = value; } 15 } 16 }
  • MockClassLib工程:提供BaseEntityAppleCatPerson
    • 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
      PropNameToInfo = new Dictionary
      (); 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
      NullValue = new Dictionary
      () 33 { 34 { "String", String.Empty }, 35 { "DateTime", DateTime.MinValue}, 36 { "Decimal", Decimal.MinValue} 37 }; 38 }
    • AppleCatPerson类:测试类,继承于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
(); //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
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
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
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
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 }

转载地址:http://xawox.baihongyu.com/

你可能感兴趣的文章
《c程序设计语言》读书笔记-3.4-数字转字符串
查看>>
Pig的安装和简单使用
查看>>
三个获取浏览器URL中参数值的方法
查看>>
堆/密文/树
查看>>
CQOI2019(十二省联考)游记
查看>>
Linux安装gitbook
查看>>
Eclipse错误提示: Symbol 'xxxx' could not be resolved
查看>>
购物商城Web开发第十二天
查看>>
解决hash冲突的方法
查看>>
winform记事本初步实现
查看>>
python利用unittest进行测试用例执行的几种方式
查看>>
js倒计时
查看>>
新手向:从不同的角度来详细分析Redis
查看>>
Nodejs介绍及其安装
查看>>
谈谈java的BlockingQueue
查看>>
性能监控和分析工具--nmon
查看>>
[转]Java + TestNG + Appium 实现单机多个Android终端并发测试
查看>>
C++ this Pointer implicit parameter
查看>>
CVPR 2007 Learning to detect a salient object
查看>>
parted命令详解
查看>>