• 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(" property.Name: " + property.Name + " property.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(" property.Name: " + property.Name + " property.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工程:提供BaseEntityAppleCatPerson
      • 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 }
        复制代码
      • AppleCatPerson类:测试类,继承于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(" >>>>>>>>>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(" >>>>>>>>>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... ");
    76 #endregion
    77 }
    78
    79 public static void ShowList(IList list)
    80 {
    81 Console.WriteLine("Type of list: {0} Count of current list: {1} Type of item in list: {2} ",
    82 list.GetType(),
    83 list.Count,
    84 list[0].GetType());
    85 }
    86 }
    87 }
    复制代码
  • 相关阅读:
    python之使用openpyxl从excel读取测试数据004
    python之编写HttpRequest工具类003
    python之cookies获取002
    OJ练习9——T20 valid parentheses
    OJ练习8——T19 remove nth node
    OJ练习7——T14 Longest Common Prefix
    OJ练习6——T8
    OJ练习5——T6
    OJ练习4——T7
    九度OJ-1351
  • 原文地址:https://www.cnblogs.com/smiler/p/10177356.html
Copyright © 2020-2023  润新知