Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Экспорт списка списков C # в Excel

Автор вопроса: MattОтветов: 4

Есть ли прямой способ экспортировать список списков (т.е. List<List<T>>) в Excel 2003 с помощью C #?

Я разбираю большие текстовые файлы и экспортирую в 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;

Это работает, но я бы предпочел использовать список непосредственно в Excel, чем выполнять промежуточный шаг по созданию массива только для Excel. Любые идеи?

listgeneric-listexcel

Ответы

Ответ 1 · рейтинг 10 · Mike Rosenblum

Стратегически вы делаете это правильно. Как говорит Джо, гораздо быстрее выполнять присвоение значений ячейкам, передавая весь массив значений за один раз, а не просматривая ячейки одну за другой.

Excel основан на COM и поэтому работает с Excel через взаимодействие .NET. К сожалению, при взаимодействии не используются универсальные шаблоны, поэтому вы не можете передать ему список ‹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) Не используйте интерфейсы _Worksheet или _Workbook. Используйте вместо этого Worksheet или Workbook. См. Обсуждение здесь: Взаимодействие с Excel: _Worksheet или 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 не делает то, что вы думаете. (См. Файлы справки здесь). Пользователь может управлять 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;

Надеюсь это поможет...

Майк

Ответ 2 · рейтинг 1 · Joe

Намного быстрее передать двумерный массив в Excel, чем обновлять ячейки по одной.

Создайте двумерный массив объектов со значениями из вашего списка списков, измените размер диапазона Excel на размеры вашего массива, а затем вызовите range.set_Value, передав двумерный массив.

Ответ 3 · Rizwan Patel

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

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

надеюсь, что это поможет

где cs.getcompletionreport() - файл эталонного класса - это бизнес-уровень для приложения.

Ответ 4 · Stana Macala

Для будущих искателей: это правда, что если вы хотите скопировать список, чтобы преуспеть, вам нужно вставить object[,] (2-мерный). На всякий случай, если у кого-то есть одномерный список, вы можете запустить только один 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];
}

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы