学习反射之将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 = "\t";
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

 

转载于:https://www.cnblogs.com/HaifengCai/p/4000314.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值