• 学习反射之将List<T>自定义导出


    学习反射之将List<T>自定义导出

    1.前言:最近有个Task需要操作很多大表(每个表的列名都上百),需要将这些表数据从不同数据源中找到,然后将表导入到数据库,可能还得需要将表部分数据导出成各种文件(csv,txt,excel等)。

     

    2.思考:一般像这种需求.先定义一个TemplateInfo,然后去DB为这个TemplateInfo创建一个表。最后封装TemplateManager定义一些操作DB的方法。

    现在问题产生了:需要经常导出表中部分数据。有时候导出titles可能有细微变化。由于TemplateInfo有很多属性,每次光复制粘贴TemplateInfo属性赋值那部分代码就够花时间的了,跟不用说让有点强迫症的人每次面对几乎差不多代码了。

      首先我们是不知道List<T>中T的具体类型,所以只能通过反射获取T的属性和值,在通过传递参数实现自定义,按照不同的参数条件,顺序,得到一组属性和对应值。然后直接生成文件。

     

    3.ReflectionUtil类,定义一组反射相关的方法

     1     public class ReflectionUtil
     2     {
     3         /// <summary>
     4         /// Get template public property name collection
     5         /// </summary>
     6         /// <param name="dateType">template type</param>
     7         /// <returns>property name collection</returns>
     8         public static List<string> GetPropertyNames<T>(T dateType)
     9         {
    10             if (dateType == null)
    11             {
    12                 throw new Exception("parameter cannot be null.");
    13             }
    14 
    15             var propertyName = new List<string>();
    16             Type type = dateType.GetType();
    17             PropertyInfo[] properties = type.GetProperties();
    18             foreach (var property in properties)
    19             {
    20                 propertyName.Add(property.Name.ToString());
    21             }
    22 
    23             return propertyName;
    24         }
    25 
    26         /// <summary>
    27         /// Get property adn set func
    28         /// </summary>
    29         /// <param name="dataType">template type</param>
    30         /// <param name="propertyName">property name</param>
    31         /// <returns></returns>
    32         public static Func<object, object> GetPropertySetFunc(Type dataType, string propertyName)
    33         {
    34             var propInfo = dataType.GetProperty(propertyName);
    35             var getMethodInfo = propInfo.GetGetMethod();
    36 
    37             DynamicMethod dynamicGet = CreateGetDynamicMethod(dataType);
    38             ILGenerator getGenerator = dynamicGet.GetILGenerator();
    39 
    40             getGenerator.Emit(OpCodes.Ldarg_0);
    41             getGenerator.Emit(OpCodes.Call, getMethodInfo);
    42             BoxIfNeeded(getMethodInfo.ReturnType, getGenerator);
    43             getGenerator.Emit(OpCodes.Ret);
    44 
    45             return dynamicGet.CreateDelegate(typeof(Func<object, object>)) as Func<object, object>;
    46         }
    47 
    48         /// <summary>
    49         /// Create get dynamic method
    50         /// </summary>
    51         /// <param name="type">template type</param>
    52         /// <returns></returns>
    53         private static DynamicMethod CreateGetDynamicMethod(Type type)
    54         {
    55             return new DynamicMethod("DynamicGet", typeof(object), new[] { typeof(object) }, type, true);
    56         }
    57 
    58         /// <summary>
    59         /// Box
    60         /// </summary>
    61         /// <param name="type">template type</param>
    62         /// <param name="generator">il generator</param>
    63         private static void BoxIfNeeded(Type type, ILGenerator generator)
    64         {
    65             if (type.IsValueType)
    66             {
    67                 generator.Emit(OpCodes.Box, type);
    68             }
    69         }
    70     }
    View Code

    4.CollectionExportUtil类,封装一组重载方法,根据不同参数满足各种文件需求导出。可以减少很多代码量和时间。

      1     /// <summary>
      2     /// ExportType can be add by new requirement in the future
      3     /// </summary>
      4     public enum ExportType
      5     {
      6         TxtFile,
      7         CsvFile,
      8         NoSeparator,
      9         Space,
     10         Other
     11     }
     12 
     13     public class CollectionExportUtil
     14     {
     15         /// <summary>
     16         /// export file from property index start
     17         /// </summary>
     18         /// <typeparam name="T">template</typeparam>
     19         /// <param name="dataCollection">template collection</param>
     20         /// <param name="propertyIndexStart">property index start</param>
     21         /// <param name="exportType">content type</param>
     22         /// <returns>content string</returns>
     23         public static string GenerateExportText<T>(List<T> dataCollection, int propertyIndexStart, ExportType exportType)
     24         {
     25             int propertyIndexEnd = ReflectionUtil.GetPropertyNames(dataCollection[0]).Count() - 1;
     26             return GenerateExportText(dataCollection, propertyIndexStart, propertyIndexEnd, exportType);
     27         }
     28 
     29         /// <summary>
     30         /// export file from property index start to index end
     31         /// </summary>
     32         /// <typeparam name="T">template</typeparam>
     33         /// <param name="dataCollection">template collection</param>
     34         /// <param name="propertyIndexStart">property index start</param>
     35         /// <param name="propertyIndexEnd">property index end </param>
     36         /// <param name="exportType">file type</param>
     37         /// <returns>content string</returns>
     38         public static string GenerateExportText<T>(List<T> dataCollection, int propertyIndexStart, int propertyIndexEnd, ExportType exportType)
     39         {
     40             if (propertyIndexStart == null || propertyIndexEnd == null)
     41             {
     42                 throw new Exception("property index parameter cannot be null.");
     43             }
     44 
     45             if (propertyIndexStart.CompareTo(0) < 0)
     46             {
     47                 throw new Exception("property index start must more than zero.");
     48             }
     49 
     50             if (propertyIndexStart.CompareTo(propertyIndexEnd) > 0)
     51             {
     52                 throw new Exception("property index start must less than index end.");
     53             }
     54 
     55             Dictionary<string, string> columnInfos = new Dictionary<string, string>();
     56             var columns = ReflectionUtil.GetPropertyNames(dataCollection[0]);
     57 
     58             if (propertyIndexEnd.CompareTo(columns.Count) > 0)
     59             {
     60                 throw new Exception("index end cannot bigger than column count.");
     61             }
     62 
     63             for (int i = propertyIndexStart; i <= propertyIndexEnd; i++)
     64             {
     65                 columnInfos.Add(columns[i], columns[i]);
     66             }
     67 
     68             return GenerateExportText(dataCollection, columnInfos, exportType);
     69         }
     70 
     71         /// <summary>
     72         /// Export by template property index list with property name
     73         /// </summary>
     74         /// <typeparam name="T">template</typeparam>
     75         /// <param name="dataCollection">template collection</param>
     76         /// <param name="indexs">property index with sequence </param>
     77         /// <param name="separator">separator</param>
     78         /// <returns>content string</returns>
     79         public static string GenerateExportText<T>(List<T> dataCollection, List<int> indexs, ExportType exportType)
     80         {
     81             if (indexs == null)
     82             {
     83                 throw new Exception("parameter cannot be null.");
     84             }
     85 
     86             Dictionary<string, string> columnInfos = new Dictionary<string, string>();
     87             var columns = ReflectionUtil.GetPropertyNames(dataCollection[0]);
     88             for (int i = 0; i < indexs.Count; i++)
     89             {
     90                 columnInfos.Add(columns[indexs[i]], columns[indexs[i]]);
     91             }
     92 
     93             return GenerateExportText(dataCollection, columnInfos, exportType);
     94         }
     95 
     96         /// <summary>
     97         /// Export by template property index list with sequence
     98         /// </summary>
     99         /// <typeparam name="T">template</typeparam>
    100         /// <param name="dataCollection">template collection</param>
    101         /// <param name="indexs">property index with sequence </param>
    102         /// <param name="titles">title of the property with sequence</param>
    103         /// <param name="separator">separator</param>
    104         /// <returns>content string</returns>
    105         public static string GenerateExportText<T>(List<T> dataCollection, List<int> indexs, List<string> titles, ExportType exportType)
    106         {
    107             if (indexs == null || titles == null)
    108             {
    109                 throw new Exception("parameter cannot be null.");
    110             }
    111 
    112             if (indexs.Count != titles.Count)
    113             {
    114                 throw new Exception("index count not equal the titles count.");
    115             }
    116 
    117             Dictionary<string, string> columnInfos = new Dictionary<string, string>();
    118             var columns = ReflectionUtil.GetPropertyNames(typeof(T));
    119             for (int i = 0; i < indexs.Count; i++)
    120             {
    121                 columnInfos.Add(titles[i], columns[indexs[i]]);
    122             }
    123 
    124             return GenerateExportText(dataCollection, columnInfos, exportType);
    125         }
    126 
    127         /// <summary>
    128         /// Export by template with all property name as the titles
    129         /// </summary>
    130         /// <typeparam name="T">template</typeparam>
    131         /// <param name="dataCollection">template collection</param>
    132         /// <param name="separator">separator</param>
    133         /// <returns>content string</returns>
    134         public static string GenerateExportText<T>(List<T> dataCollection, ExportType exportType)
    135         {
    136             Dictionary<string, string> columnInfos = new Dictionary<string, string>();
    137             var columns = ReflectionUtil.GetPropertyNames(dataCollection[0]);
    138             foreach (var item in columns)
    139             {
    140                 columnInfos.Add(item, item);
    141             }
    142 
    143             return GenerateExportText(dataCollection, columnInfos, exportType);
    144         }
    145 
    146         /// <summary>
    147         /// Export by template with (title,property)
    148         /// </summary>
    149         /// <typeparam name="T">template</typeparam>
    150         /// <param name="dataCollection">template collection</param>
    151         /// <param name="columnInfos">(title,property) collection</param>
    152         /// <param name="separator">separator</param>
    153         /// <returns>content string</returns>
    154         public static string GenerateExportText<T>(List<T> dataCollection, Dictionary<string, string> columnInfos, ExportType exportType)
    155         {
    156             StringBuilder fullText = new StringBuilder();
    157             var headers = columnInfos.Select(p => p.Key);
    158 
    159             string separator = string.Empty;
    160             switch (exportType)
    161             {
    162                 case ExportType.TxtFile:
    163                     separator = "	";
    164                     break;
    165                 case ExportType.CsvFile:
    166                     separator = ",";
    167                     break;
    168                 case ExportType.NoSeparator:
    169                     separator = "";
    170                     break;
    171                 case ExportType.Space:
    172                     separator = " ";
    173                     break;
    174             }
    175 
    176             //add title
    177             fullText.AppendLine(string.Join(separator, headers));
    178 
    179             if (dataCollection == null)
    180             {
    181                 return fullText.ToString();
    182             }
    183 
    184             Dictionary<string, Func<object, object>> delegateMap = new Dictionary<string, Func<object, object>>();
    185             Type dataType = typeof(T);
    186 
    187             foreach (var pair in columnInfos)
    188             {
    189                 string propertyName = pair.Value;
    190                 delegateMap.Add(propertyName, ReflectionUtil.GetPropertySetFunc(dataType, propertyName));
    191             }
    192 
    193             foreach (var data in dataCollection)
    194             {
    195                 List<string> values = new List<string>();
    196 
    197                 foreach (var pair in columnInfos)
    198                 {
    199                     string propertyName = pair.Value;
    200                     var getValueFunc = delegateMap[propertyName];
    201                     values.Add(getValueFunc.Invoke(data).ToString());
    202                 }
    203 
    204                 //add value
    205                 fullText.AppendLine(string.Join(separator, values));
    206             }
    207 
    208             return fullText.ToString();
    209         }
    210 
    211         /// <summary>
    212         /// genetate file
    213         /// </summary>
    214         /// <param name="content"></param>
    215         /// <param name="path"></param>
    216         public static void GenerateExportFile(string content, string path)
    217         {
    218             File.WriteAllText(path, content, Encoding.Default);
    219         }
    220 
    221         /// <summary>
    222         /// generate file with encoding type
    223         /// </summary>
    224         /// <param name="content"></param>
    225         /// <param name="path"></param>
    226         /// <param name="encoding"></param>
    227         public static void GenerateExportFile(string content, string path, Encoding encoding)
    228         {
    229             if ((path + "").Trim().Length == 0)
    230             {
    231                 throw new Exception("path of generated cannot be empty.");
    232             }
    233 
    234             if (!Directory.Exists(Path.GetDirectoryName(path)))
    235             {
    236                 Directory.CreateDirectory(Path.GetDirectoryName(path));
    237             }
    238 
    239             File.WriteAllText(path, content, encoding);
    240         }
    241     }
    View Code

    5.使用举例:Demon

      5.1 对于表:AutoDivInsertBulkLoaderInfo

      1     public class AutoDivInsertBulkLoaderInfo
      2     {
      3         public string RicEventType { get; set; }//key of the table}
      4         public string URL { get; set; }
      5         public string AnnualOrSemiAnnualReport { get; set; }
      6         public string RIC { get; set; }
      7         public string DVP_TYPE { get; set; }
      8         public string CLA_EVENT_STATUS { get; set; }
      9         public string FPE_PERIOD_END { get; set; }
     10         public string FPE_PERIOD_LENGTH { get; set; }
     11         public string DIVIDEND_AMOUNT { get; set; }
     12         public string ANNOUNCEMENT_DATE { get; set; }
     13         public string PAY_DATE { get; set; }
     14         public string RECORD_DATE { get; set; }
     15         public string EX_DATE { get; set; }
     16         public string PAYDATE_DAY_SET { get; set; }
     17         public string PAID_AS_PERCENT { get; set; }
     18         public string CLA_CUR_VAL { get; set; }
     19         public string QDI_PERCENT { get; set; }
     20         public string DESCRIPTION { get; set; }
     21         public string CLA_MEETING_TYPE_VAL { get; set; }
     22         public string MEETING_DATE { get; set; }
     23         public string CLA_TAX_STATUS_VAL { get; set; }
     24         public string TAX_RATE_PERCENT { get; set; }
     25         public string FOREIGN_INVESTOR_TAX_RATE { get; set; }
     26         public string SOURCE_TYPE { get; set; }
     27         public string RELEASE_DATE { get; set; }
     28         public string LOCAL_DATE { get; set; }
     29         public string TIMEZONE_NAME { get; set; }
     30         public string SOURCE_PROVIDER { get; set; }
     31         public string BRIDGE_SYMBOL { get; set; }
     32         public string SEQ_NUM { get; set; }
     33         public string CLA_RECORD_STATUS { get; set; }
     34         public string FPE_PERIOD_LENGTH_INDICATOR { get; set; }
     35         public string CLA_DIV_MARKER_VAL { get; set; }
     36         public string CLA_DIV_FREQ_VAL { get; set; }
     37         public string PID_QUARTER { get; set; }
     38         public string PID_YEAR { get; set; }
     39         public string PID { get; set; }
     40         public string CLA_TEXT_TYPE { get; set; }
     41         public string CLA_DIV_FEATURES_VAL { get; set; }
     42         public string TAX_CREDIT_PERCENT { get; set; }
     43         public string CLA_TAX_TRTMNT_MKR_VAL { get; set; }
     44         public string RESCINDED { get; set; }
     45         public string CAC_MA_COMMENTS { get; set; }
     46         public string FRANKED_PERCENT { get; set; }
     47         public string REINVESTMENT_PLAN_AVAILABLE { get; set; }
     48         public string REINVESTMENT_DEADLINE { get; set; }
     49         public string REINVESTMENT_PRICE { get; set; }
     50         public string CLA_SOURCE_OF_FUND { get; set; }
     51         public string CLA_DIV_RANKING { get; set; }
     52         public string DIVIDEND_RANKING_DATE { get; set; }
     53         public string BOOKCLOSURE_START_DATE { get; set; }
     54         public string BOOKCLOSURE_END_DATE { get; set; }
     55         public string MODIFIED { get; set; }
     56         public string SOURCE_ID { get; set; }
     57         public string SOURCE_LINK { get; set; }
     58         public string SOURCE_DESCRIPTION { get; set; }
     59 
     60         public AutoDivInsertBulkLoaderInfo()
     61         {
     62             //this.RicEventType = string.Empty;//key
     63             this.URL = string.Empty;
     64             this.AnnualOrSemiAnnualReport = string.Empty;
     65             //this.RIC = string.Empty;
     66             //this.DVP_TYPE = string.Empty;
     67             this.CLA_EVENT_STATUS = string.Empty;
     68             this.FPE_PERIOD_END = string.Empty;
     69             this.FPE_PERIOD_LENGTH = string.Empty;
     70             this.DIVIDEND_AMOUNT = string.Empty;
     71             this.ANNOUNCEMENT_DATE = string.Empty;
     72             this.PAY_DATE = string.Empty;
     73             this.RECORD_DATE = string.Empty;
     74             this.EX_DATE = string.Empty;
     75             this.PAYDATE_DAY_SET = string.Empty;
     76             this.PAID_AS_PERCENT = string.Empty;
     77             this.CLA_CUR_VAL = string.Empty;
     78             this.QDI_PERCENT = string.Empty;
     79             this.DESCRIPTION = string.Empty;
     80             this.CLA_MEETING_TYPE_VAL = string.Empty;
     81             this.MEETING_DATE = string.Empty;
     82             this.CLA_TAX_STATUS_VAL = string.Empty;
     83             this.TAX_RATE_PERCENT = string.Empty;
     84             this.FOREIGN_INVESTOR_TAX_RATE = string.Empty;
     85             this.SOURCE_TYPE = string.Empty;
     86             this.RELEASE_DATE = string.Empty;
     87             this.LOCAL_DATE = string.Empty;
     88             this.TIMEZONE_NAME = string.Empty;
     89             this.SOURCE_PROVIDER = string.Empty;
     90             this.BRIDGE_SYMBOL = string.Empty;
     91             this.SEQ_NUM = string.Empty;
     92             this.CLA_RECORD_STATUS = string.Empty;
     93             this.FPE_PERIOD_LENGTH_INDICATOR = string.Empty;
     94             this.CLA_DIV_MARKER_VAL = string.Empty;
     95             this.CLA_DIV_FREQ_VAL = string.Empty;
     96             this.PID_QUARTER = string.Empty;
     97             this.PID_YEAR = string.Empty;
     98             this.PID = string.Empty;
     99             this.CLA_TEXT_TYPE = string.Empty;
    100             this.CLA_DIV_FEATURES_VAL = string.Empty;
    101             this.TAX_CREDIT_PERCENT = string.Empty;
    102             this.CLA_TAX_TRTMNT_MKR_VAL = string.Empty;
    103             this.RESCINDED = string.Empty;
    104             this.CAC_MA_COMMENTS = string.Empty;
    105             this.FRANKED_PERCENT = string.Empty;
    106             this.REINVESTMENT_PLAN_AVAILABLE = string.Empty;
    107             this.REINVESTMENT_DEADLINE = string.Empty;
    108             this.REINVESTMENT_PRICE = string.Empty;
    109             this.CLA_SOURCE_OF_FUND = string.Empty;
    110             this.CLA_DIV_RANKING = string.Empty;
    111             this.DIVIDEND_RANKING_DATE = string.Empty;
    112             this.BOOKCLOSURE_START_DATE = string.Empty;
    113             this.BOOKCLOSURE_END_DATE = string.Empty;
    114             this.MODIFIED = string.Empty;
    115             this.SOURCE_ID = string.Empty;
    116             this.SOURCE_LINK = string.Empty;
    117             this.SOURCE_DESCRIPTION = string.Empty;
    118         }
    119     }
    View Code

      5.2 需求导出从URL开始(第2个属性)按升顺方式将AutoDivInsertBulkLoaderInfo所有属性的值导出,且属性AnnualOrSemiAnnualReport的Title改为

      ”Annual/Semi-annual Report“,其他Title 等于默认属性名。

     1         private void GenerateAutoDivInsertBulkLoaderBulkFile(List<AutoDivInsertBulkLoaderInfo> autoinsertBulkFile)
     2         {
     3             if (autoinsertBulkFile == null || autoinsertBulkFile.Count == 0)
     4             {
     5                 Logger.Log("autoinsertBulkFile collection is empty, neednot to generate autoinsertBulkFile.csv file.", Logger.LogType.Warning);
     6                 return;
     7             }
     8 
     9             Dictionary<string, string> titles = new Dictionary<string, string>();
    10             var property = Ric.Util.ReflectionUtil.GetPropertyNames(autoinsertBulkFile[0]);
    11             for (int i = 0; i < property.Count; i++)
    12             {
    13                 if (i == 0)
    14                     continue;
    15 
    16                 if (i == 2)
    17                     titles.Add("Annual/Semi-annual Report", property[i]);
    18                 else
    19                     titles.Add(property[i], property[i]);
    20             }
    21 
    22             string path = Path.Combine(resultPath, DateTime.Now.ToString("dd-MM-yyyy"));
    23             string fileName = Path.Combine(path, string.Format("AUTO_DIV_Insert_Bulk_Loader_{0}.csv", DateTime.Now.ToString("dd-MM-yyyy")));
    24             CollectionExportUtil.GenerateExportFile(CollectionExportUtil.GenerateExportText(autoinsertBulkFile, titles, ExportType.CsvFile), fileName);
    25         }
    View Code
  • 相关阅读:
    国内最火的3款前端开发框架
    Cordova是做什么的
    老师你好。使用cordova生成的hellowold 的安卓5.0版本太高。怎么才可以生成4.4的呢?
    一个类似bootstrap的foundation
    role在标签中的作用是什么?
    如何做到根据不同的进度用不同的颜色显示整个进度条
    wall 和panel有啥区别
    git ignore
    eclipse js 引用跳转
    计划
  • 原文地址:https://www.cnblogs.com/HaifengCai/p/4000314.html
Copyright © 2020-2023  润新知