使用具有匿名类型的LoadFromCollection进行epplus

我有一个IEnumerable dataSource,它包含一个匿名类型的集合。 在设计时不会知道匿名类型的实际结构,所以我试图找到一个可以处理任何匿名类型的通用解决方案。

如何将它们加载到epplus中以创建电子表格? 我有一个名为ws的工作表,我尝试过:

 ws.Cells["A1"].LoadFromCollection(dataSource, true); 

但是,当它运行时,它会将所有匿名类型的属性输出到单个单元格中:

 { Id = 10000, Title = This is a test } 

我尝试使用以下方法传递MemberInfo:

 var members = dataSource.First().GetType().GetMembers(); ws.Cells["A1"].LoadFromCollection(this._dataSource, true, TableStyles.Medium1, BindingFlags.Public, members); 

但这引发了一个例外:

参数Properties中提供的属性必须与T的类型相同

关于如何使用c#中的匿名类型创建电子表格的任何建议?

您可以对匿名类型进行分组,以便使用dataTables轻松导出。 错误 “参数属性中提供的属性必须与T的类型相同”仍然存在,并且解决方法是使用DataTables。

 // Imagine list is your main datasource IEnumerable list = Enumerable.Empty(); // Data Source of  // Added anon types at runtime added to the object list var anonTypesOne = new object[] { new { GuidID = Guid.NewGuid(), StringProperty = "the string property" }, new { IntegerID = 1, IntegerProperty = 99 } }; var anonTypesTwo = new object[] { new { StringID = "1", BooleanProperty = true, NumberProperty = 3, StringProperty = "Four" }, new { GuidID = Guid.NewGuid(), NumberThree = 3 }, new { GuidID = Guid.NewGuid(), NumberThree = 3 }, new { GuidID = Guid.NewGuid(), NumberThree = 3 } }; list = list.Concat(anonTypesOne).Concat(anonTypesTwo); // Grouping works on anon types so we can group the export into their own tables var groupings = list.GroupBy(i => i.GetType()); using(var package = new ExcelPackage(new FileInfo("C:\\Temp\\Anon.xlsx"))) { var ws = package.Workbook.Worksheets.Add("Anonymous Types"); // add each "anon type matched grouping" foreach(var grouping in groupings) { var isNew = ws.Dimension == null; // the sheet is empty if Dimension is null. var row = 0; if(isNew) { row = 1; // start from the first row } else { // otherwise there are tables already, start from the bottom row = ws.Dimension.End.Row; } // because of EPP inheritance bug of T, we can just use dataTable DataTable dt = new DataTable(grouping.Key.Name); var properties = grouping.Key.GetProperties(); // Get anon type Properties foreach(var property in properties) { dt.Columns.Add(property.Name); } foreach(var item in grouping.ToList()) { var dataRow = dt.NewRow(); foreach(var p in properties) // populate a single row { dataRow[p.Name] = p.GetValue(item); // item is anon object instance } dt.Rows.Add(dataRow); } if(isNew) // load into the top most left cell of the worksheet ws.Cells[1, 1].LoadFromDataTable(dt, PrintHeaders: true); else // load from the dimension of current items + 1 row for spacing ws.Cells[ws.Dimension.End.Row + 1, 1].LoadFromDataTable(dt, PrintHeaders: true); ws.InsertRow(ws.Dimension.End.Row + 2, 5); // Insert some padding between each group } package.Save(); } 

我测试过了

 using (var excel = new OfficeOpenXml.ExcelPackage()) { var sheet = excel.Workbook.Worksheets.Add("Test"); sheet.Cells["A1"].LoadFromCollection(dataSource, true); excel.SaveAs(new FileInfo(@"C:\Temp\Test.xlsx")); } 

使用此示例数据:

 var dataSource = Enumerable.Range(1, 100).Select(i => new{ ID=i, Title="Title " + i }); 

它工作正常。 它创建两列具有正确的标题和100行。

但是,只有在编译时知道结构时才应使用匿名类型。

您可以使用DataTableLoadFromDataTable 。 由于我不知道你是如何创建匿名类型的,我只展示了一个小样本:

 DataTable dataSource = new DataTable(); dataSource.Columns.Add("Id"); // default type is string dataSource.Columns.Add("Title"); // add other columns dataSource.Rows.Add("1", "Title1"); // add other rows using (var excel = new OfficeOpenXml.ExcelPackage()) { var sheet = excel.Workbook.Worksheets.Add("Test"); sheet.Cells["A1"].LoadFromDataTable(dataSource, true); excel.SaveAs(new FileInfo(@"C:\Temp\Test.xlsx")); } 

我是,这个post比较老,但我正在寻找同样的问题。 使用以下代码(VB),我获得了成功。 卡斯滕

  Dim targetFile = New IO.FileInfo(sFN) Dim dataSource = Enumerable.Range(0, 1).Select(Function(i) New With {.ID = 1000, .Titel = "This is a test "}).ToList Using epp = New OfficeOpenXml.ExcelPackage(targetFile) Dim ws = epp.Workbook.Worksheets.Add("lst_Anonymous") ws.Cells(1, 1).LoadFromCollection(dataSource, True, OfficeOpenXml.Table.TableStyles.Medium1, Reflection.BindingFlags.Public, dataSource.GetType.GetGenericArguments()(0).GetProperties) epp.Save() End Using