如何用OpenXML将任意泛型List<T>填充至Excel工作表(无需映射)
使用OpenXML将泛型集合List导出为带类型的Excel工作表
以下是实现任意泛型集合导出为符合要求的Excel文件的完整方案,包含类型映射、列标题格式化功能:
核心实现代码
首先引入必要的命名空间:
using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Spreadsheet; using System; using System.Collections.Generic; using System.Reflection;
通用导出方法
public static void ExportListToExcel<T>(List<T> dataList, string filePath) { using (SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(filePath, SpreadsheetDocumentType.Workbook)) { // 初始化工作簿和工作表 WorkbookPart workbookPart = spreadsheetDocument.AddWorkbookPart(); workbookPart.Workbook = new Workbook(); WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>(); worksheetPart.Worksheet = new Worksheet(new SheetData()); // 关联工作表到工作簿 Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets()); sheets.Append(new Sheet { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "数据列表" }); SheetData sheetData = worksheetPart.Worksheet.GetFirstChild<SheetData>(); PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance); // 写入列标题行 Row headerRow = new Row(); foreach (var prop in properties) { string headerText = prop.Name.Replace("_", " "); headerRow.Append(CreateCell(headerText, CellValues.String)); } sheetData.Append(headerRow); // 写入数据行 foreach (var item in dataList) { Row dataRow = new Row(); foreach (var prop in properties) { object value = prop.GetValue(item); CellValues cellType = GetCellValueType(prop.PropertyType); dataRow.Append(CreateCell(value, cellType)); } sheetData.Append(dataRow); } workbookPart.Workbook.Save(); } }
辅助方法
// 创建指定类型的单元格 private static Cell CreateCell(object value, CellValues cellType) { Cell cell = new Cell { DataType = new EnumValue<CellValues>(cellType), CellValue = new CellValue(value?.ToString() ?? string.Empty) }; return cell; } // 映射.NET类型到Excel单元格类型 private static CellValues GetCellValueType(Type type) { Type baseType = Nullable.GetUnderlyingType(type) ?? type; return baseType switch { Type t when t == typeof(string) => CellValues.String, Type t when t == typeof(int) || t == typeof(long) || t == typeof(short) || t == typeof(float) || t == typeof(double) || t == typeof(decimal) => CellValues.Number, Type t when t == typeof(DateTime) => CellValues.Date, Type t when t == typeof(bool) => CellValues.Boolean, _ => CellValues.String }; }
使用示例
针对你提供的Lines类:
internal class Lines { public string Tipo_de_Línea { get; set; } public long Total { get; set; } } // 构造测试数据并导出 var linesData = new List<Lines> { new Lines { Tipo_de_Línea = "本地线路", Total = 500 }, new Lines { Tipo_de_Línea = "跨境线路", Total = 1200 } }; ExportListToExcel(linesData, @"D:\output\线路统计.xlsx");
关键特性说明
- 泛型适配:通过反射获取任意类的属性信息,无需为每个类单独编写导出逻辑。
- 列标题格式化:自动将属性名中的下划线替换为空格,如
Tipo_de_Línea转为Tipo de Línea。 - 类型保留:严格映射.NET数据类型到Excel单元格类型,字符串对应TEXT、数值类型对应NUMBER,确保Excel中数据类型正确。
- 空值处理:自动处理属性值为null的情况,避免导出异常。
内容的提问来源于stack exchange,提问作者Leandro Bardelli
相关产品推荐
相关产品推荐

