C#动态调用泛型类、泛型方法
2012-03-13 14:16
525 查看
在制作一个批量序列化工具时遇到了如下问题,在此记录一下,仅供参考。
主程序加载另一个程序集,将其中的所有类取出,然后对这些类分别调用泛型类或泛型方法。控制台程序解决方案如下:
Main工程:提供Worker类进行数据操作,XMLTool<T>泛型类将数据集序列化为.xml文档,RootCollection<T>类封装数据集
Worker类
提供成员方法void DoWork<T>()、List<T> GetList<T>()、静态成员方法StaticDoWork<T>(),代码如下:
[b]XMLTool<T>类[/b]
RootCollection<T>类:
MockClassLib工程:提供BaseEntity、Apple、Cat和Person类
BaseEntity类:抽象类,负责初始化类成员
Apple、Cat和Person类:测试类,继承于BaseEntity
Main工程的Program的Main方法中,一般情况下,调用Worker的泛型方法来处理测试类的话,可以写为:
Worker worker = new Worker();
worker.DoWork<Apple>();
worker.DoWork<Cat>();
worker.DoWork<Person>();
但是,如果MockClassLib中需要处理的类型非常多时,这样显示调用必然是不灵活的,应当怎样向泛型方法DoWork<T>()的尖括号中动态传入类型呢?
考虑代码:
可以看到,Type类型的实例是无法直接传入泛型方法的尖括号中的,T要求显式指明类型名。
下面通过反射方式来获取泛型方法,并创建特定类型的泛型方法。
对于非静态方法:public void DoWork<T>()
对于非静态方法,调用MethodInfo.Invoke(object, object[])时,第一个参数需要指明泛型方法的所有者(即这里创建的worker对象),第二个参数为泛
型方法的参数列表,DoWork<T>()没有输入参数,所以设为null
对于静态方法:public static void StaticDoWork<T>()
不同于非静态方法,这里直接反射的类静态方法,所以Invoke()的第一个参数设为null
对于有返回值的非静态方法:public List<T> GetList()
如同动态调用DoWork<T>()方法一样,只是在处理返回值时,可以使用下面的方法
对于泛型类:XMLTool<T>
下面要使用泛型类XMLTool<T>的静态方法public static void XmlSerialize_Save(List<T> list, string dirPath, string fileName)方法。
首先应通过反射构造出指定类型的泛型类XMLTool<T>,再反射出其中的XmlSerialize_Save方法并使用。
Program-->Main()方法的全部代码:
[b]相关文章:[/b]
关于MackGenericMethod()方法
关于MethodInfo.Invoke()(+2)方法
Overcoming problems with MethodInfo.Invoke of methods with by-reference value type arguments
How to: Define a Generic Type with Reflection Emit
主程序加载另一个程序集,将其中的所有类取出,然后对这些类分别调用泛型类或泛型方法。控制台程序解决方案如下:
Main工程:提供Worker类进行数据操作,XMLTool<T>泛型类将数据集序列化为.xml文档,RootCollection<T>类封装数据集
Worker类
提供成员方法void DoWork<T>()、List<T> GetList<T>()、静态成员方法StaticDoWork<T>(),代码如下:
public class Worker { public Worker() { } public void DoWork<T>() { Type t = typeof(T); Console.WriteLine("Get Class: {0}", t.Name); PropertyInfo[] properties = t.GetProperties(); foreach (PropertyInfo property in properties) { Console.WriteLine("\tproperty.Name: " + property.Name + "\tproperty.MemberType: " + property.PropertyType); } } public static void StaticDoWork<T>() { Type t = typeof(T); Console.WriteLine("Get Class: {0}", t.Name); PropertyInfo[] properties = t.GetProperties(); foreach (PropertyInfo property in properties) { Console.WriteLine("\tproperty.Name: " + property.Name + "\tproperty.MemberType: " + property.PropertyType); } } public List<T> GetList<T>() { Console.WriteLine("Generate List for [{0}]", typeof(T).Name); return new List<T>() { Activator.CreateInstance<T>(), Activator.CreateInstance<T>() }; } }
[b]XMLTool<T>类[/b]
publicclass XMLTool<T> { publicstaticvoid XmlSerialize_Save(List<T> needSerializedList, string xmlDirPath, string xmlFileName) { RootCollection<T> collection = new RootCollection<T>(); collection.ItemList = needSerializedList; if (!Directory.Exists(xmlDirPath)) Directory.CreateDirectory(xmlDirPath); using (System.IO.FileStream stream = new System.IO.FileStream(xmlFileName, System.IO.FileMode.Create)) { System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(collection.GetType()); serializer.Serialize(stream, collection); } } }
RootCollection<T>类:
[Serializable] public class RootCollection<T> { public RootCollection() { itemList = new List<T>(); } private List<T> itemList; public List<T> ItemList { get { return itemList; } set { itemList = value; } } }
MockClassLib工程:提供BaseEntity、Apple、Cat和Person类
BaseEntity类:抽象类,负责初始化类成员
1 public abstract class BaseEntity { 3 public BaseEntity() { InitiaWithNull(); } 8 private void InitiaWithNull() { Type type = this.GetType(); PropertyInfo[] properties = type.GetProperties(); 12 string[] PropNames = new string[properties.Length]; Dictionary<string, PropertyInfo> PropNameToInfo = new Dictionary<string, PropertyInfo>(); 14 for (int i = 0; i < properties.Length; i++) { PropNames[i] = properties[i].Name; PropNameToInfo.Add(PropNames[i], properties[i]); } 20 foreach (string propname in PropNames) { 22 string proptype = PropNameToInfo[propname].PropertyType.Name; 24 object value = null; 25 if (NullValue.Keys.Contains(proptype)) value = NullValue[proptype]; type.GetProperty(propname).SetValue(this, value, null); } } 32 private static readonly Dictionary<string, object> NullValue = new Dictionary<string, object>() { { "String", String.Empty }, { "DateTime", DateTime.MinValue}, { "Decimal", Decimal.MinValue} }; }
Apple、Cat和Person类:测试类,继承于BaseEntity
1 public class Apple : BaseEntity { 3 public string Color { get; set; } } 6 public class Cat : BaseEntity { 8 public string Type { get; set; } } 11 public class Person : BaseEntity { 13 public int ID { get; set; } 14 public string Name { get; set; } }
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>()方法一样,只是在处理返回值时,可以使用下面的方法
IList tempList = (IList)curMethod.Invoke(worker, null); //Or 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方法并使用。
//Use Generic Class Type xmlToolType = typeof(XMLTool<>).MakeGenericType(curType); //Get method MethodInfo saveMethod = xmlToolType.GetMethod("XmlSerialize_Save"); //Invoke saveMethod.Invoke ( null, //Static method new object[] { resultList, @"c:\", @"c:\Test_" + curType.Name + ".xml" } );
Program-->Main()方法的全部代码:
namespace RetrieveUnknownClass { class Program { static void Main(string[] args) { //Load assembly Assembly mockAssembly = Assembly.LoadFrom("MockClassLibrary.dll"); Type[] typeArray = mockAssembly.GetTypes(); //Create instance of Worker Type workerType = typeof(Worker); Worker worker = new Worker(); #region Member method Console.WriteLine(">>>>>>>>>Use Generic Method:"); MethodInfo doWorkMethod = workerType.GetMethod("DoWork"); //Invoke DoWork<T> foreach (Type curType in typeArray) { if (curType.IsClass && !curType.IsAbstract) { MethodInfo curMethod = doWorkMethod.MakeGenericMethod(curType); curMethod.Invoke(worker, null);//Member method,use instance } } #endregion #region Static method Console.WriteLine("\r\n>>>>>>>>>Use Static 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 } } #endregion #region Get A List & Serialize It to Xml File With Generic Console.WriteLine("\r\n>>>>>>>>>Get List By Generic Method:"); MethodInfo getListMethod = workerType.GetMethod("GetList"); foreach (Type curType in typeArray) { if (curType.IsClass && !curType.IsAbstract) { MethodInfo curMethod = getListMethod.MakeGenericMethod(curType); //Generate List IList resultList = (IList)curMethod.Invoke(worker, null); //Show List ShowList(resultList); //Use Generic Class Type xmlToolType = typeof(XMLTool<>).MakeGenericType(curType); MethodInfo saveMethod = xmlToolType.GetMethod("XmlSerialize_Save"); saveMethod.Invoke ( null, //Static method new object[] { resultList, @"c:\", @"c:\Test_" + curType.Name + ".xml" } ); } } Console.WriteLine("Serialization Completed...\r\n"); #endregion } public static void ShowList(IList list) { Console.WriteLine("Type of list: {0}\r\nCount of current list: {1}\r\nType of item in list: {2}\r\n", list.GetType(), list.Count, list[0].GetType()); } } }
[b]相关文章:[/b]
关于MackGenericMethod()方法
关于MethodInfo.Invoke()(+2)方法
Overcoming problems with MethodInfo.Invoke of methods with by-reference value type arguments
How to: Define a Generic Type with Reflection Emit
相关文章推荐
- C# 使用反射动态调用泛型方法
- Net下采用GET/POST/SOAP方式动态调用WebService的简易灵活方法(C#)
- C#调用C++动态链接库方法介绍
- 关于C#动态调用VC Dll的方法(转)
- c# 动态加载dll文件,并实现调用其中的方法(推荐)
- C#反射动态调用dll中的方法,并返回结果
- C#实现反射调用动态加载的DLL文件中的方法
- c#动态加载dll并调用dll中类的方法
- 深入理解 c# 第三章 通过反射来调用和获取泛型方法
- (.net)C#动态调用Web服务的几种方法
- C#动态加载ActiveX控件并调用指定的方法
- SVG格式转Visio的vsd(x)格式方法,附带C#动态调用Office的Com组件方法
- C#实现反射调用动态加载的DLL文件中的方法
- .Net下采用GET/POST/SOAP方式动态调用WebService的简易灵活方法(C#) [轉]Redfox
- C#反射动态调用dll中的方法
- 使用C#反射中的MakeGenericType函数,来为泛型方法和泛型类指定(泛型的)类型
- C#动态方法调用
- C#反射动态调用dll中的方法,并返回结果
- 【转】C#动态方法调用
- .Net下采用GET/POST/SOAP方式动态调用WebService的简易灵活方法(C#)