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)
{
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 }

C#动态调用泛型类、泛型方法的更多相关文章
- 采用异步来实现重新连接服务器或者重新启动服务 C#中类的属性的获取 SignalR2简易数据看板演示 C#动态调用泛型类、泛型方法 asp .net core Get raw request. 从壹开始前后端分离[.NetCore 不定期更新] 38 ║自动初始化数据库
采用异步来实现重新连接服务器或者重新启动服务 开启异步监听,不会导致主线程的堵塞,在服务异常断开后一直检测重新连接服务,成功连接服务后通知各个注册的客户端! #region 检测断线并重连OPC服务 ...
- 动态调用WebService
WebService内容 using Microsoft.CSharp;using System;using System.CodeDom;using System.CodeDom.Compiler; ...
- c# 动态调用WCF方法笔记!
//动态调用wcf方法 string url = "http://localhost:54379/ServiceWCF.svc"; IDoubleService proxy = W ...
- C# 动态调用DLL库
最近经常用到C#动态调用类库,简单的做下记录方便以后查询. 使用下面的几行代码就可以简单实现DLL类库的调用了 using System.Reflection; // 引入该命名空间 // 获取roc ...
- Atitit 动态调用webservice与客户端代理方式调用
Atitit 动态调用webservice与客户端代理方式调用 方式1: 使用call.invoke 直接调用WSDL,缺点:麻烦,不推荐--特别是JAVA调用.NET的WS时,会有不少的问题需要解 ...
- StructureMap.dll 中的 GetInstance 重载 + 如何利用 反射动态创建泛型类
public static T GetInstance<T>(ExplicitArguments args); // // Summary: // Creates a new instan ...
- C#动态调用WCF接口,两种方式任你选。
写在前面 接触WCF还是它在最初诞生之处,一个分布式应用的巨作. 从开始接触到现在断断续续,真正使用的项目少之又少,更谈不上深入WCF内部实现机制和原理去研究,最近自己做一个项目时用到了WCF. 从这 ...
- 11月10日上午ajax基础知识、用ajax做登录页面、用ajax验证用户名是否可用、ajax动态调用数据库
1.ajax的基础知识 ajax是结合了jquery.php等几种技术延伸出来的综合运用的技术,不是新的内容.ajax也是写在<script>标签里面的. 如果使用ajax一定是要有1个处 ...
- C# 调用WebService的3种方式 :直接调用、根据wsdl生成webservice的.cs文件及生成dll调用、动态调用
1.直接调用 已知webservice路径,则可以直接 添加服务引用--高级--添加web引用 直接输入webservice URL.这个比较常见也很简单 即有完整的webservice文件目录如下图 ...
随机推荐
- 115个Java面试题和答案——终极列表(下)【转】
第一篇讨论了面向对象编程和它的特点,关于Java和它的功能的常见问题,Java的集合类,垃圾收集器,本章主要讨论异常处理,Java小应用程序,Swing,JDBC,远程方法调用(RMI),Servle ...
- android sqlite android.database.CursorIndexOutOfBoundsException: Index 5 requested, with a size of 5
Cursor c = db.query("user",null,null,null,null,null,null);//查询并获得游标 if(c.moveToFirst()){// ...
- __new__()方法的使用和实例化
Python中__new__()方法的使用和实例化 1 2 new()是在新式类中新出现的方法,它作用在构造方法init()建造实例之前,可以这么理解,在Python 中存在于类里面的构造方法init ...
- 关于Java的散列桶, 以及附上一个案例-重写map集合
为速度而散列: SlowMap.java说明了创建一个新的Map并不困难.但正如它的名称SlowMap所示,它不会很快,如果有更好的选择就应该放弃它.它的问题在于对键的查询,键没有按照任何特定的顺序保 ...
- Spring BeanWrapper分析
最近在读DispatcherServlet 源代码,看到父级类org.springframework.web.servlet.HttpServletBean中关于BeanWrapper的一段代码, 继 ...
- Java公开课-05.log4j
log4j 一,log4j简介 1.如果程序中出现异常,我们怎么解决? 01.使用异常处理机制===>异常 (但是使用原则是,能不用异常处理机制,最好不用,怎么办?) 02.通过debug调试 ...
- Spring Boot 使用 Log4j2
Java 中比较常用的日志工具类,有 Log4j.SLF4j.Commons-logging(简称jcl).Logback.Log4j2(Log4j 升级版).Jdk Logging. Spring ...
- 安装ipset车祸现场
基础环境centos6.8内核2.6.32. 本身服务器带的是6.11ipset版本,业务需求,需要升级到6.32 ipset-6.32 ./configure 报错 configure: error ...
- SPU和SKU有什么区别
SPU = Standard Product Unit (标准产品单位)SPU是商品信息聚合的最小单位,是一组可复用.易检索的标准化信息的集合,该集合描述了一个产品的特性.通俗点讲,属性值.特性相同的 ...
- BZOJ_2809_[Apio2012]dispatching_可并堆
BZOJ_2809_[Apio2012]dispatching_可并堆 Description 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿.在这个帮派里,有一名忍者被称 ...