[C#] 匯出IEnumerable<T>至Excel

[C#] 匯出IEnumerable<T>至Excel


前言


匯出Excel檔案是一個很常見的需求,

通常我們都會需要將Gridview中的資料匯出成Excel檔,

除了在Asp.Net中常見的直接使用Response.Write匯出之外,

我們也可以使用NPOI的Library來動態產生Excel檔案以供下載,

所以今天希望可以替IEnumerable<T>撰寫一個擴充方法,

來動態的產生Excel檔案,並能夠根據Attribute修改欄位名稱,

在AP或Web上都能夠通用

 

實際演練


首先,我們先準備一個欲匯出資料的Class,

並且我們引用System.ComponentDataModel.DataAnnotations的dll,

替我們的Class加上DisplayName,也就是我們所希望顯示的Title名稱


    [DisplayName("員工資料")]
    public class PersonData
    {
        [DisplayName("員工序號")]
        public int Sn { get; set; }

        [DisplayName("員工姓名")]
        public string Name { get; set; }

        [DisplayName("員工生日")]
        public DateTime BirthDay { get; set; }        
    }

接著,我們來替IEnumerable<T>撰寫擴充方法,

使得IEnumerable<T>都擁有匯出Excel的能力,

在這邊使用了NPOI Library,請大家記得引用相關的dll

(NPOI, NPOI.HSSF, NPOI.POIFS, NPOI.Util)


    public static class ExportExcelExtensions
    {
        public static void ExportExcel<T>(this IEnumerable<T> dataList, string fileName)
        {
            //Create workbook
            var datatype = typeof(T);
            var workbook = new HSSFWorkbook();
            var worksheet = workbook.CreateSheet(string.Format("{0}", datatype.GetDisplayName()));

            //Insert titles
            var row = worksheet.CreateRow(0);
            var titleList = datatype.GetPropertyDisplayNames();
            for (int i = 0; i < titleList.Count; i++)
            {
                row.CreateCell(i).SetCellValue(titleList[i]);
            }

            //Insert data values
            for (int i = 1; i < dataList.Count() + 1; i++)
            {
                var tmpRow = worksheet.CreateRow(i);
                var valueList = dataList.ElementAt(i - 1).GetPropertyValues();

                for (int j = 0; j < valueList.Count; j++)
                {
                    tmpRow.CreateCell(j).SetCellValue(valueList[j]);
                }
            }

            //Save file
            FileStream file = new FileStream(fileName, FileMode.Create);
            workbook.Write(file);
            file.Close();
        }

        public static string GetDisplayName(this MemberInfo memberInfo)
        {            
            var titleName = string.Empty;

            //Try get DisplayName
            var attribute = memberInfo.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault();
            if (attribute != null)
            {
                titleName = (attribute as DisplayNameAttribute).DisplayName;
            }
            //If no DisplayName
            else
            {
                titleName = memberInfo.Name;
            }

            return titleName;
        }

        public static List<string> GetPropertyDisplayNames(this Type type)
        {
            var titleList = new List<string>();
            var propertyInfos = type.GetProperties();

            foreach (var propertyInfo in propertyInfos)
            {
                var titleName = propertyInfo.GetDisplayName();

                titleList.Add(titleName);
            }

            return titleList;
        }

        public static List<string> GetPropertyValues<T>(this T data)
        {
            var propertyValues = new List<string>();
            var propertyInfos = data.GetType().GetProperties();

            foreach (var propertyInfo in propertyInfos)
            {
                propertyValues.Add(propertyInfo.GetValue(data, null).ToString());
            }

            return propertyValues;
        }
    }

ExportExcel : 用來匯出Excel檔案

GetDisplayName : 取得DisplayNameAttribute中所設定的名稱

GetPropertyDisplayNames : 取得Property的顯示名稱,用來當作標題

GetPropertyValues : 取得Property的值

 

使用範例:


            var dataList = new List<PersonData>()
            {
                new PersonData(){Sn=1,Name="John",BirthDay=new DateTime(1985,6,8)},
                new PersonData(){Sn=2,Name="David",BirthDay=new DateTime(1979,2,14)},
                new PersonData(){Sn=3,Name="Steve",BirthDay=new DateTime(1988,3,9)},
            };

            dataList.ExportExcel("Test.xls");

匯出結果 :

55

 

結語


當然這個擴充方法還可以依照更進一步的需求作變更,

比如說顯示格式,欄位寬度,或是挑選欲顯示屬性等等,

大家可以依照自己的需求作擴充,

如果有任何問題請跟我說 ^^