這是本文的第四部分也是最後部分,適合新人初步學習泛型、反射,提供了有限的業務場景分析、若干的NPOI接口使用示范,前三部分鏈接如下:
接第三部分,由於單元格設置語句僅簡單的一句話row.CreateCell(i).SetCellValue(value.ToString()),生成的Excel仍然粗陋。
Excel導出通常會遇到若干問題:
ICell的實現者HSSFCell有數量不少的屬性和方法幫助我們完成單元格格式設置,考慮到應用場景,創建指定類型的單元格並配合格式化選項已經能滿足要求,下文使用若干強制轉型和控制語句完成功能。
首先擴充Header類,添加一個Format參數。當使用者傳入空Format參數時由我們推斷單元格類型與值,而當使用者傳入非空的Format參數時,我們調用ToString(String format)方法進行格式化。
String Name { ; String PrintName { ; String Format { ; (name, printName, ===
我們把權力交給調用者時,便認為他的參數傳遞是經過判斷且有道理的,比如純數字的條形碼顯示可能需要調用Decimal.ToString("F0")方法,,但使用者對薪水調用ToString("P2")顯示百分號就沒辦法了;另一部分是設計之初的問題,如雙精度Double型精確度,後面再說。
由於ICell.CreateCell(int column, CellType type)創建的單元格類型最終由ICell.SetCellValue()重載版本中參數類型(可以是Boolean、DateTime、Double、String及IRichTextString)決定,所以統一只使用了ICell.CreateCell(int column),必須注意的是用於存放數值的單元格類型枚舉只有CellType.NUMERIC,下文還要講到。新的Export改動點如剛才描述,舊的Person類及Export重載請見前文,實現如下:
IWorkbook Export<T>(IList<T> records, IList<Header> (records == ArgumentNullException( (headers == ArgumentNullException(); = (Int32 i = ; i < headers.Count; i++= (T).GetProperty(headers[i].Name); = = = (Int32 r = ; r < records.Count; r++ ((r % RowPerSheet) == = (Int32)((Double)r / RowPerSheet) + = workbook.CreateSheet( + sheetIndex); row = sheet.CreateRow(); (Int32 i = ; i < headers.Count; i++= sheet.CreateRow((r % RowPerSheet) + ); (Int32 i = ; i < props.Length; i++ (props[i] != ) = props[i].GetValue(records[r], (value != ) = (props[i].PropertyType == (props[i].PropertyType == (props[i].PropertyType == (props[i].PropertyType == (Int32 i = ; i < workbook.NumberOfSheets; i++= (Int32 h = ; h < headers.Count; h++
生日類數據顯示到年月日即可,我們使用"yyyy-MM-dd"作為格式化參數,薪水未提供格式化參數,客戶端調用代碼如下:
Main(= <Person> persons = List<Person> (Int32 i = ; i < records; i++= = i + = + (i + = Math.Abs(Guid.NewGuid().GetHashCode() % ) + =<ExcelHelper.Header> headers = List<ExcelHelper.Header> ExcelHelper.Header( ExcelHelper.Header(, ExcelHelper.Header(, , ExcelHelper.Header(, = = = = excelHelper.Export<Person> (FileStream stream =
之前提到過雙精度的問題,對某個員工的薪酬設置為1234567890123456並輸出Excel會怎麼樣,先做個測試:
Person person = new Person(); person.Salary = 1234567890123456; Console.WriteLine(person.Salary);
輸出結果是1.23456789012346E+15也就是說Excel上不僅顯示的是科學計數法,而且數值已經變成悲了個劇的1234567890123460。粗暴地講,這是因為雙精度的Double型的有效位數造成的,並不是ToString方法或者Excel寫入時產生了變化。
要處理類似問題,僅將Person.Salary聲明為Decimal類型還不夠,因為單元格類型CellType枚舉中用來存數字的只有CellType.NUMERIC,沒辦法我們需要配合ToString("F0")(或者F2等視具體要求)把值當作字符串寫入單元格,改動部分的部分代碼如下:
Decimal Salary { ; = ExcelHelper.Header(, ,
於是能看到Excel上顯示的1234567890123456,雖然有綠色小三角,好歹沒變成科學計數法和四捨五入。如要求更完備請自行參考NPOI相關API,代碼文件已提供,本文完。