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文件目录如下图 ...
随机推荐
- 《T-SQL查询》读书笔记Part 2.执行计划
一.关于执行计划 执行计划是优化器生成的用于确定如何处理一个给定查询的“工作计划”.一个计划包含一组运算符,通常按照特定的顺序来应用这些运算符.此外,一些运算符可以在它们之前的运算符还在处理时被应用( ...
- no system images installed for this target这个问题如何解决?
今天想查看个项目的布局,结果发现这个Hierarchy这个工具没有提供对实体机的支持,所以就想加一个模拟机,结果还曝出了这么么一个错误,导致不能设置模拟机: 在网上的查找下,发现原来是缺失了 圈中的是 ...
- 论C++如何优雅的使用数组
C/C++中如果一个函数接受一个数组作为参数,那么数组将会被退化为指针,如果定义如下代码: //数组arr的大小未知. int arrsize(int arr*) { cout << &q ...
- [ Java面试题 ]持久层篇
1.什么是ORM? 对象关系映射(Object-Relational Mapping,简称ORM)是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术: 简单的说,ORM是通过使用描 ...
- Spring3.1 对Bean Validation规范的新支持(方法级别验证)
上接Spring提供的BeanPostProcessor的扩展点-1继续学习. 一.Bean Validation框架简介 写道Bean Validation standardizes constra ...
- SpringBoot操作数据库 2017.12.14
http://blog.csdn.net/forezp/article/details/61472783
- 16.app后端如何保证通讯安全--url签名
app和后端的通讯过程中,api请求有可能被别人截取或不小心泄露.那么,怎么保证api请求的安全呢?在这篇文章中,介绍一种常见的保证api请求安全的做法--url签名. 1. url签名详解 在前一篇 ...
- requests+selenium==requestium模块介绍
有时,你可能会在网上实现一些自动化操作.比如抓取网站,进行应用测试,或在网上填表,但又不想使用API,这时自动化就变得很必要.Python提供了非常优秀的Requests库可以辅助进行这些操作.可惜, ...
- 根据高德API知道坐标获取详细地址信息
/** * 根据坐标获取具体地址 * @param coor 坐标字符串 * @return */ public static String getAdd(String coor){ String u ...
- Prometheus监控⼊⻔简介
文档目录: • prometheus是什么?• prometheus能为我们带来些什么• prometheus对于运维的要求• prometheus多图效果展示 1) Prometheus是什么pro ...