【问题标题】:epplus using LoadFromCollection with anonymous typesepplus 使用带有匿名类型的 LoadFromCollection
【发布时间】:2014-07-02 14:47:02
【问题描述】:

我有一个 IEnumerable<object> 数据源,其中包含一个集合匿名类型。匿名类型的实际结构在设计时是未知的,所以我试图找到一个可以处理任何匿名类型的通用解决方案。

如何将它们加载到 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# 中使用匿名类型创建电子表格有什么建议吗?

【问题讨论】:

  • 显示你初始化dataSource的代码
  • 真的,您根本不应该在这里使用匿名类型。当它们的结构在编译时已知时,它们被设计为静态使用。你最好构造一些匿名类型以外的东西,这些东西是为在不知道静态模式的情况下使用而设计的。
  • @TimSchmelter 用于初始化的代码会有所不同,但一个简单的示例如下:ReportData = new ProductRepository(this.DbContext).AllItems.Where(p => p.IsStocked).Select(p => new {p.Id, p.Title }).ToList(); 抱歉,格式有点乱。

标签: c# epplus


【解决方案1】:

我已经测试过了

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

【讨论】:

  • 这从 DataTables 开始,但对于更复杂的 DataTable,代码变得有点大。因此,尝试寻找替代匿名类型,而我认为应该有效的方法却没有,将对象的属性输出为单个单元格。如果不起作用,我将尝试使用 ExpandoObject 进行测试,它将返回到 DataTable。非常感谢您的帮助。
【解决方案2】:

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

// Imagine list is your main datasource
IEnumerable<object> list = Enumerable.Empty<object>(); // Data Source of <object>

// 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();
}

【讨论】:

  • 现在我明白了!我使用了一个稍微修改过的版本,可枚举集合中的所有匿名类型都将具有相同的属性。我还在列创建中添加了 PropertyType,以便以后可以格式化电子表格列。
【解决方案3】:

我是,这个线程较旧,但我正在寻找同样的问题。 使用以下代码(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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多