C# NPOI數據導出到Excel之反射

  之前努力去理解過反射,但是項目中幾乎用不到反射,所以對反射理解效果很差。正好最近做了一個類庫,功能是將數據導出到Excel,裏面用到了反射。我覺得這個是理解反射比較好的案例,所以將此記錄下來。

  反射理解:反射是.NET中的重要機制,通過反射,可以在運行時獲得程序或程序集中每一個類型(包括類、結構、委託、接口和枚舉等)的成員和成員的信息。

  下面的程序功能是將一組數據導出到ExcelList<T>導出到Excel

  這裏實體T以下面(StudentEntity)的簡單例子來理解:

    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表格如下:

  

  分析一下:

  在這裏動態變化的只有T

  表格第1行是固定的表頭信息,是一種合併單元格的形式,合併的列數也就是T的字段數量;

  表格第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;
        }
    }
}

  以上只是反射很小的一個應用,個人覺得對理解反射比較有幫助。

  以上代碼可能還有需要改進之處,歡迎批評改正。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章