4

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

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

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

这是我想替换或改进的代码片段:

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;

这行得通,但我宁愿直接将 List 用于 Excel,而不是仅仅为了 Excel 而创建数组的中间步骤。有任何想法吗?

4

4 回答 4

10

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

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

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

(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) 不要使用_Worksheetor_Workbook接口。使用WorksheetorWorkbook代替。请参阅此处进行讨论:Excel 互操作:_Worksheet 还是 Worksheet?.

(3) 考虑使用C#中的Range.Resize方法。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.UserControltrue。使 Excel 对用户可见就足够了。该UserControl物业并没有像您认为的那样做。(请参阅此处的帮助文件)如果您想控制用户是否可以控制 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;

希望这可以帮助...

麦克风

于 2009-06-29T22:06:52.173 回答
1

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

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

于 2009-06-29T19:17:31.967 回答
0
List<"classname"> getreport = cs.getcompletionreport();

var getreported = getreport .Select(c => new { demographic = c.rName);

希望这会有所帮助

参考类文件在哪里cs.getcompletionreport()是 App 的业务层

于 2012-11-05T09:10:44.810 回答
0

对于未来的搜索者:确实,如果要将列表复制到 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];
}
于 2018-11-16T11:12:21.397 回答