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;
        }
    }
}

  以上只是反射很小的一个应用,个人觉得对理解反射比较有帮助。

  以上代码可能还有需要改进之处,欢迎批评改正。

 

 

 

 

posted on 2018-08-15 14:58  FIGHTING360  阅读(3577)  评论(4编辑  收藏