【问题标题】:Export a C# List of Lists to Excel将 C# 列表导出到 Excel
【发布时间】:2009-06-29 19:11:34
【问题描述】:

使用 C#,是否有直接的方法将列表列表(即List<List<T>>)导出到 Excel 2003?

我正在解析大型文本文件并导出到 Excel。一次写入一个单元格会产生过多的开销。我选择使用List<T>,这样我就不必担心指定行数或列数了。

目前,我等到文件结束,然后将我的 List<List<object>> 的内容放入二维数组中。然后可以将数组设置为 Excel.Range 对象的值。它有效,但似乎我应该能够获取我的列表列表,而不必担心行数或列数,只需将其转储到工作表中,从 A1 到任何地方。

这是我想替换或改进的代码的 sn-p:

object oOpt = System.Reflection.Missing.Value; //for optional arguments
Excel.Application oXL = new Excel.Application();
Excel.Workbooks oWBs = oXL.Workbooks;
Excel._Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
Excel._Worksheet oSheet = (Excel._Worksheet)oWB.ActiveSheet;

int numberOfRows = outputRows.Count;
int numberOfColumns = int.MinValue;

//outputRows is a List<List<object>>
foreach (List<object> outputColumns in outputRows)
{
        if (numberOfColumns < outputColumns.Count)
        { numberOfColumns = outputColumns.Count; }
}

Excel.Range oRng = oSheet.get_Range("A1", oSheet.Cells[numberOfRows,numberOfColumns]);

object[,] outputArray = new object[numberOfRows,numberOfColumns];

for (int row = 0; row < numberOfRows; row++)
{
        for (int col = 0; col < outputRows[row].Count; col++)
        {
                outputArray[row, col] = outputRows[row][col];
        }
}

oRng.set_Value(oOpt, outputArray);

oXL.Visible = true;
oXL.UserControl = true;

这可行,但我宁愿直接在 Excel 中使用 List,也不愿仅仅为了 Excel 而创建数组的中间步骤。有什么想法吗?

【问题讨论】:

    标签: c# .net excel list generic-list


    【解决方案1】:

    从战略上讲,你做得对。正如 Joe 所说,通过一次性传递整个值数组而不是逐个循环遍历单元格来执行单元格值分配要快得多。

    Excel 是基于 COM 的,因此通过 .NET 互操作与 Excel 一起运行。不幸的是,互操作对泛型一无所知,因此您不能将 List 等传递给它。二维数组确实是唯一的方法。

    也就是说,有几种方法可以清理您的代码,使其更易于管理。以下是一些想法:

    (1) 如果您使用的是 .NET 3.0,您可以使用 LINQ 来缩短您的代码:

    int numberOfColumns = int.MinValue;
    
    foreach (List<object> outputColumns in outputRows)
    {
            if (numberOfColumns < outputColumns.Count)
            { numberOfColumns = outputColumns.Count; }
    }
    

    到单行:

    int numberOfColumns = outputRows.Max(list => list.Count);
    

    (2) 不要使用_Worksheet_Workbook 接口。请改用WorksheetWorkbook。请参阅此处进行讨论:Excel interop: _Worksheet or Worksheet?

    (3) 考虑使用Range.Resize 方法,该方法在C# 中以Range.get_Resize 的形式出现。不过,这是一个折腾——我实际上喜欢你设置范围大小的方式。但这是我认为你可能想知道的事情。例如,您在此处的行:

    Excel.Range oRng = oSheet.get_Range("A1", oSheet.Cells[numberOfRows,numberOfColumns]);
    

    可以改为:

    Excel.Range oRng = 
        oSheet.get_Range("A1", Type.Missing)
            .get_Resize(numberOfRows, numberOfColumns);
    

    (4) 您不必将Application.UserControl 设置为true。使 Excel 对用户可见就足够了。 UserControl 属性没有按照您的想法执行。 (参见帮助文件here)如果你想控制用户是否可以控制Excel,你应该使用工作表保护,或者你可以设置Application.Interactive = false如果你想锁定你的用户。 (很少有一个好主意。)但如果您想允许用户使用 Excel,那么只需使其可见就足够了。

    总的来说,考虑到这些,我认为您的代码可能看起来像这样:

    object oOpt = System.Reflection.Missing.Value; //for optional arguments
    Excel.Application oXL = new Excel.Application();
    Excel.Workbooks oWBs = oXL.Workbooks;
    Excel.Workbook oWB = oWBs.Add(Excel.XlWBATemplate.xlWBATWorksheet);
    Excel.Worksheet oSheet = (Excel.Worksheet)oWB.ActiveSheet;
    
    //outputRows is a List<List<object>>
    int numberOfRows = outputRows.Count;
    int numberOfColumns = outputRows.Max(list => list.Count);
    
    Excel.Range oRng = 
        oSheet.get_Range("A1", oOpt)
            .get_Resize(numberOfRows, numberOfColumns);
    
    object[,] outputArray = new object[numberOfRows, numberOfColumns];
    
    for (int row = 0; row < numberOfRows; row++)
    {
        for (int col = 0; col < outputRows[row].Count; col++)
        {
            outputArray[row, col] = outputRows[row][col];
        }
    }
    
    oRng.set_Value(oOpt, outputArray);
    
    oXL.Visible = true;
    

    希望这会有所帮助...

    迈克

    【讨论】:

    • 谢谢!虽然我们不在 .NET 3.0 上,但我非常感谢您的所有澄清。
    • 没问题,很高兴它有帮助。 :-) 只有第 1 项与 .NET 3.0 有关,所有其他项都适用于任何 .NET Framework。 LINQ 是考虑迁移到 3.0 的主要原因。它不会彻底改变您的所有代码,但在某些领域 LINQ 是一个非常好的功能。
    • 谢谢!这工作完美,绝对赞成!然而,一个可能有帮助的小细节;我必须在这段代码中添加句子oXL.Quit;,因为如果没有,进程会继续运行,并且在某个时刻我开始出现错误。
    • 我希望我能给这个答案投票一百次 :)
    【解决方案2】:

    将二维数组传递给 Excel 比一次更新一个单元格要快得多。

    使用列表中的值创建一个二维对象数组,将 Excel 范围重新调整为数组的维度,然后调用 range.set_Value,传递二维数组。

    【讨论】:

    • 这就是我目前正在做的;但似乎如果我首先要使用 List&lt;T&gt; 而不是数组,那么可能还有另一种方法可以将数据导入 Excel,而无需先将其全部加载到中间数组中。
    【解决方案3】:
    List<"classname"> getreport = cs.getcompletionreport();
    
    var getreported = getreport .Select(c => new { demographic = c.rName);
    

    希望这会有所帮助

    其中cs.getcompletionreport() 是参考类文件是应用程序的业务层

    【讨论】:

      【解决方案4】:

      对于未来的搜索者:确实,如果要将列表复制到 Excel,则必须粘贴 object[,](二维)。万一有人有一维列表,您可以只运行一个for loop,第二个维度为 1:

      List<DateTime> listDate; //I'm filling it with data from datagridview
      ...
      object[,] outDate = new object[listDate.Count, 1];
      for(int row = 0; row < listDate.Count; row++)
      {
          outDate[row, 0] = listDate[row];
      }
      

      【讨论】:

        猜你喜欢
        • 2014-10-05
        • 2012-07-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多