web-dev-qa-db-ja.com

csvHelperを使用した列の動的作成

サーバーからフェッチされるさまざまなフィールドを持つワーカーがあります。このクラスをExcelシートに変換するためにCSVHelperパッケージを使用しています。ワーカーには次のようなフィールドがあります。

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シートにマップして、キー(文字列)が別の列名になり、値(オブジェクト)が列の値になるようにするにはどうすればよいですか。

CSVHelperは実行時にそれを行うのに役立ちますか?ドキュメントを確認しました。私のために働く何かを見つけることができませんでした。

10
hyoyin_Kyuoma

現時点では、辞書の作成はサポートされていないと思います。 1つには、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辞書キーがリストで一貫していない場合、コードは少し複雑になりますが、解決可能です。

18

辞書はサポートされていませんが、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

上記の最初のリンクをたどると、50行目と57行目でWriteDynamicHeaderメソッドが使用されています。

拡張メソッドを使用して、各レコードのExpandoObjectを作成し、CsvHelperを使用してそのオブジェクトを書き込みます。documentという名前のDictionary<string, object>パラメーターは、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();

これで、上記のリンクにあるJoshのテストに従って、CsvHelperとかなりシームレスに辞書を使用するために必要なすべてが揃いました。私はこれがマイケルのより良い解決策ではないと思います、ただ違うアプローチです。

クレジットは、クレジットが原因のディクショナリコードからの基本的なExpandoObjectがここにあります(詳細な説明があります!) https://www.oreilly.com/learning/building-c-objects-dynamically

5
robs