欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-17 19:19:53
在制作一个批量序列化工具时遇到了如下问题,在此记录一下,仅供参考。 主程序加载另一个程序集,将其中的所有类取出,然后对这些类分别调用泛型类或泛型方法。控制台程序解决方案如下: Main工程:提供Worker类进行数据操作,XMLTool泛型类将数据集序列化为.xml文档,RootCollect ......

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

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

  • main工程:提供worker类进行数据操作,xmltool<t>泛型类将数据集序列化为.xml文档,rootcollection<t>类封装数据集
    • worker类

           提供成员方法void dowork<t>()、list<t> getlist<t>()、静态成员方法staticdowork<t>(),代码如下:

    C#动态调用泛型类、泛型方法
     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 }
    C#动态调用泛型类、泛型方法

     

    • xmltool<t>类
      C#动态调用泛型类、泛型方法
       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 }
      C#动态调用泛型类、泛型方法
    • rootcollection<t>类:
      C#动态调用泛型类、泛型方法
       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 }
      C#动态调用泛型类、泛型方法
  • mockclasslib工程:提供baseentityapplecatperson
    • baseentity类:抽象类,负责初始化类成员
      C#动态调用泛型类、泛型方法
       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 }
      C#动态调用泛型类、泛型方法
    • applecatperson类:测试类,继承于baseentity
      C#动态调用泛型类、泛型方法
       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 }
      C#动态调用泛型类、泛型方法

 

      main工程的program的main方法中,一般情况下,调用worker的泛型方法来处理测试类的话,可以写为:

      worker worker = new worker();

      worker.dowork<apple>();

      worker.dowork<cat>();

      worker.dowork<person>();

      但是,如果mockclasslib中需要处理的类型非常多时,这样显示调用必然是不灵活的,应当怎样向泛型方法dowork<t>()的尖括号中动态传入类型呢?

      考虑代码:

C#动态调用泛型类、泛型方法
            //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
}
C#动态调用泛型类、泛型方法

      可以看到,type类型的实例是无法直接传入泛型方法的尖括号中的,t要求显式指明类型名。

      下面通过反射方式来获取泛型方法,并创建特定类型的泛型方法。

  • 对于非静态方法:public void dowork<t>()

          对于非静态方法,调用methodinfo.invoke(object, object[])时,第一个参数需要指明泛型方法的所有者(即这里创建的worker对象),第二个参数为泛

          型方法的参数列表,dowork<t>()没有输入参数,所以设为null

C#动态调用泛型类、泛型方法
//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
}
}
C#动态调用泛型类、泛型方法
  • 对于静态方法:public static void staticdowork<t>()

          不同于非静态方法,这里直接反射的类静态方法,所以invoke()的第一个参数设为null

C#动态调用泛型类、泛型方法
//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
}
}
C#动态调用泛型类、泛型方法
  • 对于有返回值的非静态方法: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方法并使用。

C#动态调用泛型类、泛型方法
 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 );
C#动态调用泛型类、泛型方法

 

       program-->main()方法的全部代码:

C#动态调用泛型类、泛型方法
 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 }
C#动态调用泛型类、泛型方法