Динамическое создание столбцов с помощью csvHelper

у меня есть работник с различными полями, которые извлекаются с сервера. Я использую пакет CSVHelper для преобразования этого класса в лист excel. Рабочий имеет такие поля, как:

class Worker
{ 
string name;
string phone;
string age;
Dictionary<string,object> customerField;
}

Я могу сопоставить имя, телефон, номер вроде

class WorkerMap : CsvClassMap<Worker>
{
public WorkerMap()
{
Map(m => m.name);
Map(m => m.phone);
Map(m => m.age);
}
}

и я генерирую карту по :

csv.Configuration.RegisterClassMap<WorkerMap>();

напишите список работников по:

csv.WriteRecords(workerList);

как я могу сопоставить словарь customerField с листом excel, чтобы ключ (строка) был другим именем столбца и значение (object) - это значение столбца.

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

2 ответов


Я не думаю, что написание словаря поддерживается в настоящее время. Во-первых, CsvHelper было бы трудно узнать, какие заголовки писать. К счастью, не слишком сложно использовать CsvWriter вручную, записывая поле за раз. Если предположить, что каждый работник имеет одинаковые ключи в customerField затем ваш код может выглядеть примерно так.

var firstWorker = workerList.First();
var keys = firstWorker.customerField.Keys.ToList();

var headers = new []{ "name", "phone", "age"}.Concat(keys).ToList();
var csv = new CsvWriter( textWriter );

// Write the headers
foreach( var header in headers )
{
    csv.WriteField(header);
}
csv.NextRecord();

// Write the rows
foreach( var item in workerList)
{
    csv.WriteField(item.name);
    csv.WriteField(item.phone);
    csv.WriteField(item.age);
    var dict = worker.customerField;
    foreach (var key in keys)
    {
        csv.WriteField(dict[key]);
    }
    csv.NextRecord();
}

этот код непроверен, но должен приблизить вас к нужному поведению. Если customerField ключи словаря не согласованы в списке, тогда код будет немного сложнее, но он все еще разрешим.


словарь не поддерживается, но поддерживается ExpandoObject.

https://github.com/JoshClose/CsvHelper/blob/48e70742e06007dae3a635c418b7e3358f667c4f/src/CsvHelper.Tests/Writing/MultipleHeadersTest.cs

https://github.com/JoshClose/CsvHelper/blob/b74a2f95a101158f4cdedd25fae6e8392b58855b/src/CsvHelper.Tests/Writing/DynamicTests.cs

если вы перейдете по первой ссылке выше, вы найдете метод WriteDynamicHeader в использовать на линиях 50 & 57.

С помощью метода расширения я создаю ExpandoObject для каждой записи и использую CsvHelper для записи этого объекта.The это то, из чего я хочу создать запись CSV.

public static class DictionaryCsvExtentions
{
    public static dynamic BuildCsvObject(this Dictionary<string, object> document)
    {
        dynamic csvObj = new ExpandoObject();

        foreach (var p in document)
        {
            AddProperty(csvObj, p.Key, p.Value);
        }

        return csvObj;
    }

    private static void AddProperty(ExpandoObject expando, string propertyName, object propertyValue)
    {
        var expandoDict = expando as IDictionary<string, object>;
        if (expandoDict.ContainsKey(propertyName))
        {
            expandoDict[propertyName] = propertyValue;
        }
        else
        {
            expandoDict.Add(propertyName, propertyValue);
        }
    }
}

теперь я могу создать ExpandoObject из моего словаря, как это

var csvObj = myDictonary.BuildCsvObject();

и с этим, после тестов Джоша в ссылке выше, у нас есть все, что нам нужно, чтобы использовать словарь довольно легко с CsvHelper. Я не думаю ... это лучшее решение для Майкла, просто другой подход.

должное основных ExpandoObject из кода словарь от Здесь (там есть много объяснений!) https://www.oreilly.com/learning/building-c-objects-dynamically