前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C#动态调用泛型类、泛型方法

C#动态调用泛型类、泛型方法

作者头像
hbbliyong
发布2018-12-28 15:45:56
2.9K0
发布2018-12-28 15:45:56
举报
文章被收录于专栏:hbbliyonghbbliyong

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

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

  • Main工程:提供Worker类进行数据操作,XMLTool<T>泛型类将数据集序列化为.xml文档,RootCollection<T>类封装数据集
    • Worker类

           提供成员方法void DoWork<T>()、List<T> GetList<T>()、静态成员方法StaticDoWork<T>(),代码如下:

代码语言:javascript
复制
 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     }
  • MockClassLib工程:提供BaseEntityAppleCatPerson
    • BaseEntity类:抽象类,负责初始化类成员
    代码语言:javascript
    复制
     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     }
    • AppleCatPerson类:测试类,继承于BaseEntity
    代码语言:javascript
    复制
     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>()的尖括号中动态传入类型呢?

      考虑代码:

代码语言:javascript
复制
            //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

代码语言:javascript
复制
//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

代码语言:javascript
复制
//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>()方法一样,只是在处理返回值时,可以使用下面的方法

代码语言:javascript
复制
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方法并使用。

代码语言:javascript
复制
 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()方法的全部代码:

代码语言:javascript
复制
 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 }
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-26 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档