将C#列表导出到Excel

时间:2009-06-29 19:11:34

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

使用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 个答案:

答案 0 :(得分:9)

战略上,你正确地做到了。正如Joe所说,通过一次性传递整个数组值而不是逐个循环遍历单元格,执行单元格值分配的速度要快得多。

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

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

(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;

希望这会有所帮助......

麦克

答案 1 :(得分:1)

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

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

答案 2 :(得分:0)

List<"classname"> getreport = cs.getcompletionreport();

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

希望这会有所帮助

其中cs.getcompletionreport()是引用类文件是App的业务层

答案 3 :(得分: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];
}