以前努力去理解過反射,可是項目中幾乎用不到反射,因此對反射理解效果不好。正好最近作了一個類庫,功能是將數據導出到Excel,裏面用到了反射。我以爲這個是理解反射比較好的案例,因此將此記錄下來。測試
反射理解:反射是.NET中的重要機制,經過反射,能夠在運行時得到程序或程序集中每個類型(包括類、結構、委託、接口和枚舉等)的成員和成員的信息。字體
下面的程序功能是將一組數據導出到Excel:List<T>導出到Excel。spa
這裏實體T如下面(StudentEntity)的簡單例子來理解:3d
public class StudentEntity { [Description("姓名")] public string name { get; set; } [Description("年齡")] public int age { get; set; } [Description("地址")] public string address { get; set; } [Description("手機號碼")] public string telphone { get; set; } }
最終輸出excel表格以下:excel
分析一下:code
在這裏動態變化的只有T;orm
表格第1行是固定的表頭信息,是一種合併單元格的形式,合併的列數也就是T的字段數量;blog
表格第2行信息是不固定的,是根據實體T裏面的字段描述來生成的(固然也能夠不用按照我這個模式來);索引
表格第3-5行就是具體的實體數據。接口
根據上面的分析獲得,咱們須要從T中獲取信息以下:
1.T的字段個數,也就是表格的列數;
2.T的字段描述,也就是第2行顯示的名稱;
在這裏就須要用到反射,當第1行和第2行產生好後,循環遍歷List<T>生成數據就能夠了。
下面就一步一步來代碼實現;
步驟1:新建一個控制檯應用程序(也能夠建類庫、winform程序);
步驟2:右擊「引用」,選擇「管理NuGet程序包」;在左面的瀏覽裏輸入NPOI,選擇最新的版本安裝就能夠了,我這裏選擇的是「最新穩定版2.3.0」;
步驟3:定義方法:
/// <summary> /// 導出數據到Excel /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data">數據集合</param> /// <param name="head">表頭(第一行數據)</param> /// <param name="sheetName">sheet名稱</param> static void ExportToExcel<T>(List<T> data, string head, string sheetName) { }
步驟4:建立一個工做簿(表):
static void ExportToExcel<T>(List<T> data, string head, string sheetName) { IWorkbook wb = new HSSFWorkbook(); //設置工做簿的名稱 sheetName = string.IsNullOrEmpty(sheetName) ? "sheet1" : sheetName; //建立一個工做簿 ISheet sh = wb.CreateSheet(sheetName); }
把引用添加上:
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
步驟5:設置前2行(表頭+擡頭)
整體預覽:(代碼爲第9行如下)
1 static void ExportToExcel<T>(List<T> data, string head, string sheetName) 2 { 3 IWorkbook wb = new HSSFWorkbook(); 4 //設置工做簿的名稱 5 sheetName = string.IsNullOrEmpty(sheetName) ? "sheet1" : sheetName; 6 //建立一個工做簿 7 ISheet sh = wb.CreateSheet(sheetName); 8 9 //全局索引 10 int gloal_index = 0; 11 System.Reflection.PropertyInfo[] oProps = null; 12 foreach (T en in data) 13 { 14 if (oProps == null) 15 { 16 oProps = ((Type)en.GetType()).GetProperties(); 17 } 18 if (gloal_index == 0) 19 { 20 #region 表頭(第1行) 21 //... 22 #endregion 23 24 #region 擡頭(第2行) 25 //... 26 #endregion 27 28 gloal_index = 2; 29 } 30 31 #region 這裏是List<T>具體內容 32 //... 33 #endregion 34 35 gloal_index++; 36 } 37 38 }
首先經過反射獲取到T的信息,其中列數的值就是oProps.Length;
前兩行的設置有gloal_index變量來控制,gloal_index爲0時,即循環第一次執行時,初始化前兩行數據,而後置gloal_index的值爲2,即正常處理List<T>的數據。
5.1 表頭裏的代碼:
#region 表頭(第1行) //合併單元格 sh.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, oProps.Length - 1)); //建立第1行 IRow row0 = sh.CreateRow(0); //設置第1行高度 row0.Height = 20 * 20; //建立第1行第1列 ICell icell1top0 = row0.CreateCell(0); //設置第1行第1列格式 icell1top0.CellStyle = Getcellstyle(wb, "head"); //設置第1行第1列內容 icell1top0.SetCellValue(head); #endregion
5.2 擡頭(第2行)的代碼:
#region 擡頭(第2行) //建立第2行 IRow row1 = sh.CreateRow(1); //設置高度 row1.Height = 20 * 20; //columnt_index是列的索引 int columnt_index = 0; foreach (System.Reflection.PropertyInfo item in oProps) { //獲取T的字段名稱 string name = item.Name; //獲取T的字段名稱的描述 string des = ((DescriptionAttribute)Attribute.GetCustomAttribute(item, typeof(DescriptionAttribute))).Description; //建立第2行的第columnt_index列 ICell icell1top = row1.CreateCell(columnt_index); //設置第2行的第columnt_index列的格式 icell1top.CellStyle = Getcellstyle(wb, ""); //設置第2行的第columnt_index列的內容 if (!string.IsNullOrEmpty(des)) { cell1top.SetCellValue(des); } else { icell1top.SetCellValue(name); } //設置第2行的第columnt_index列的寬度 sh.SetColumnWidth(columnt_index, (int)((15 + 0.72) * 256)); columnt_index++; } #endregion
步驟6:設置主體內容(除前兩行外)
#region 這裏是List<T>具體內容 //建立第gloal_index行 IRow row_zs = sh.CreateRow(gloal_index); int column_index = 0; foreach (System.Reflection.PropertyInfo pi in oProps) { //建立第gloal_index行的第columnt_index列 ICell icell1top = row_zs.CreateCell(column_index); //設置第gloal_index行的第columnt_index列格式 icell1top.CellStyle = Getcellstyle(wb, ""); //獲取en字段值 string v_value = pi.GetValue(en, null) == null ? "" : pi.GetValue(en, null).ToString(); //設置第gloal_index行的第columnt_index列的內容 icell1top.SetCellValue(v_value); column_index++; } #endregion
步驟7:輸出數據
//輸出內容 using (FileStream stm = File.OpenWrite(@"D:\studentInfo.xls")) { wb.Write(stm); }
格式設置方法Getcellstyle以下:
/// <summary> /// 格式設置 /// </summary> static ICellStyle Getcellstyle(IWorkbook wb, string type) { ICellStyle cellStyle = wb.CreateCellStyle(); //定義字體 IFont font = wb.CreateFont(); font.FontName = "微軟雅黑"; //水平對齊 cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Left; //垂直對齊 cellStyle.VerticalAlignment = VerticalAlignment.Center; //自動換行 cellStyle.WrapText = true; //縮進 cellStyle.Indention = 0; switch (type) { case "head": cellStyle.SetFont(font); cellStyle.Alignment = HorizontalAlignment.Center; break; default: cellStyle.SetFont(font); break; } return cellStyle; }
步驟8:以T爲StudentEntity爲例生成測試數據:
static void Main(string[] args) { StudentEntity se1 = new StudentEntity() { name = "張三", age = 20, address = "上海", telphone = "16278171615" }; StudentEntity se2 = new StudentEntity() { name = "李四", age = 18, address = "北京", telphone = "19278187590" }; StudentEntity se3 = new StudentEntity() { name = "王五", age = 19, address = "廣州", telphone = "18278187590" }; List<StudentEntity> selist = new List<StudentEntity>(); selist.Add(se1); selist.Add(se2); selist.Add(se3); ExportToExcel<StudentEntity>(selist, "學生信息", "學生信息表"); Console.WriteLine("ok"); Console.Read(); }
完整代碼以下:
using NPOI.HSSF.UserModel; using NPOI.HSSF.Util; using NPOI.SS.UserModel; using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ExcelReflection { class Program { static void Main(string[] args) { StudentEntity se1 = new StudentEntity() { name = "張三", age = 20, address = "上海", telphone = "16278171615" }; StudentEntity se2 = new StudentEntity() { name = "李四", age = 18, address = "北京", telphone = "19278187590" }; StudentEntity se3 = new StudentEntity() { name = "王五", age = 19, address = "廣州", telphone = "18278187590" }; List<StudentEntity> selist = new List<StudentEntity>(); selist.Add(se1); selist.Add(se2); selist.Add(se3); ExportToExcel<StudentEntity>(selist, "學生信息", "學生信息表"); Console.WriteLine("ok"); Console.Read(); } /// <summary> /// 導出數據到Excel /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data">數據集合</param> /// <param name="head">表頭(第一行數據)</param> /// <param name="sheetName">sheet名稱</param> static void ExportToExcel<T>(List<T> data, string head, string sheetName) { IWorkbook wb = new HSSFWorkbook(); //設置工做簿的名稱 sheetName = string.IsNullOrEmpty(sheetName) ? "sheet1" : sheetName; //建立一個工做簿 ISheet sh = wb.CreateSheet(sheetName); //全局索引 int gloal_index = 0; System.Reflection.PropertyInfo[] oProps = null; foreach (T en in data) { if (oProps == null) { oProps = ((Type)en.GetType()).GetProperties(); } if (gloal_index == 0) { #region 表頭(第1行) //合併單元格 sh.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, oProps.Length - 1)); //建立第1行 IRow row0 = sh.CreateRow(0); //設置第1行高度 row0.Height = 20 * 20; //建立第1行第1列 ICell icell1top0 = row0.CreateCell(0); //設置第1行第1列格式 icell1top0.CellStyle = Getcellstyle(wb, "head"); //設置第1行第1列內容 icell1top0.SetCellValue(head); #endregion #region 擡頭(第2行) //建立第2行 IRow row1 = sh.CreateRow(1); //設置高度 row1.Height = 20 * 20; //columnt_index是列的索引 int columnt_index = 0; foreach (System.Reflection.PropertyInfo item in oProps) { //獲取T的字段名稱 string name = item.Name; //獲取T的字段名稱的描述 string des = ((DescriptionAttribute)Attribute.GetCustomAttribute(item, typeof(DescriptionAttribute))).Description; //建立第2行的第columnt_index列 ICell icell1top = row1.CreateCell(columnt_index); //設置第2行的第columnt_index列的格式 icell1top.CellStyle = Getcellstyle(wb, ""); //設置第2行的第columnt_index列的內容 if (!string.IsNullOrEmpty(des)) { icell1top.SetCellValue(des); } else { icell1top.SetCellValue(name); } //設置第2行的第columnt_index列的寬度 sh.SetColumnWidth(columnt_index, (int)((15 + 0.72) * 256)); columnt_index++; } #endregion gloal_index = 2; } #region 這裏是List<T>具體內容 //建立第gloal_index行 IRow row_zs = sh.CreateRow(gloal_index); int column_index = 0; foreach (System.Reflection.PropertyInfo pi in oProps) { //建立第gloal_index行的第columnt_index列 ICell icell1top = row_zs.CreateCell(column_index); //設置第gloal_index行的第columnt_index列格式 icell1top.CellStyle = Getcellstyle(wb, ""); //獲取en字段值 string v_value = pi.GetValue(en, null) == null ? "" : pi.GetValue(en, null).ToString(); //設置第gloal_index行的第columnt_index列的內容 icell1top.SetCellValue(v_value); column_index++; } #endregion gloal_index++; } //輸出內容 using (FileStream stm = File.OpenWrite(@"D:\studentInfo.xls")) { wb.Write(stm); } } /// <summary> /// 格式設置 /// </summary> static ICellStyle Getcellstyle(IWorkbook wb, string type) { ICellStyle cellStyle = wb.CreateCellStyle(); //定義字體 IFont font = wb.CreateFont(); font.FontName = "微軟雅黑"; //水平對齊 cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.Left; //垂直對齊 cellStyle.VerticalAlignment = VerticalAlignment.Center; //自動換行 cellStyle.WrapText = true; //縮進 cellStyle.Indention = 0; switch (type) { case "head": cellStyle.SetFont(font); cellStyle.Alignment = HorizontalAlignment.Center; break; default: cellStyle.SetFont(font); break; } return cellStyle; } } }
以上只是反射很小的一個應用,我的以爲對理解反射比較有幫助。
以上代碼可能還有須要改進之處,歡迎批評改正。