Skip to content

Instantly share code, notes, and snippets.

@runceel
Last active April 30, 2021 07:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save runceel/f72668f997d133864cb1df8a9ebc501c to your computer and use it in GitHub Desktop.
Save runceel/f72668f997d133864cb1df8a9ebc501c to your computer and use it in GitHub Desktop.
using CsvHelper;
using CsvHelper.Configuration;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
namespace ConsoleApp8
{
class Program
{
static void Main(string[] args)
{
using var sw = new StringWriter();
var config = new CsvConfiguration(CultureInfo.CurrentCulture)
{
HasHeaderRecord = false,
};
using var writer = new CsvWriter(sw, config);
// 出力用のテストデータ
var orders = Enumerable.Range(0, 10).Select(x => new Orders
{
Id = x,
// 偶数行と奇数行で DiscountsDetails の件数を変えています。(3項演算子なので見づらいですが…)
DiscountsDetails = x % 2 == 0 ?
new List<DiscountsDetails>
{
new DiscountsDetails{ dataA = "a value of dataA-1", dataB = "a value of dataB-1" },
new DiscountsDetails{ dataA = "a value of dataA-2", dataB = "a value of dataB-2" },
} :
new List<DiscountsDetails>
{
new DiscountsDetails{ dataA = "a value of dataA-1", dataB = "a value of dataB-1" },
new DiscountsDetails{ dataA = "a value of dataA-2", dataB = "a value of dataB-2" },
new DiscountsDetails{ dataA = "a value of dataA-3", dataB = "a value of dataB-3" },
new DiscountsDetails{ dataA = "a value of dataA-4", dataB = "a value of dataB-4" },
}
});
// CSV に出力するときは Orders クラスではなく OrdersDynamicObject にして CSV に出力する
writer.WriteRecords(orders.Select(x => new OrdersDynamicObject(x)));
Console.WriteLine(sw.ToString());
}
}
// CSV に出力するクラス
public class Orders
{
public int Id { get; set; }
public List<DiscountsDetails> DiscountsDetails { get; set; }
}
public class DiscountsDetails
{
public string dataA { get; set; }
public string dataB { get; set; }
}
// CsvHelper の dynamic オブジェクトを CSV に出力する機能を使って実行時に動的に CSV に出力するプロパティを決める DynamicObject
// https://joshclose.github.io/CsvHelper/examples/writing/write-dynamic-objects/
public class OrdersDynamicObject : DynamicObject
{
private readonly Orders _orders;
public OrdersDynamicObject(Orders orders)
{
_orders = orders;
}
public override IEnumerable<string> GetDynamicMemberNames()
{
return new[] { nameof(Orders.Id) }
.Concat(
_orders.DiscountsDetails
?.SelectMany(
(x, i) => new[] { $"{nameof(DiscountsDetails)}${i}${nameof(DiscountsDetails.dataA)}", $"{nameof(DiscountsDetails)}${i}${nameof(DiscountsDetails.dataB)}" }) ?? Array.Empty<string>());
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
if (binder.Name == nameof(Orders.Id))
{
result = _orders.Id;
return true;
}
else
{
var tokens = binder.Name.Split('$');
if (tokens.Length == 3 && tokens[0] == nameof(DiscountsDetails) && int.TryParse(tokens[1], out var index))
{
var obj = _orders.DiscountsDetails[index];
var (ok, value) = tokens[2] switch
{
nameof(DiscountsDetails.dataA) => (true, obj.dataA),
nameof(DiscountsDetails.dataB) => (true, obj.dataB),
_ => (false, null),
};
result = value;
return ok;
}
}
// 正しくないプロパティ名
result = null;
return false;
}
}
}
We can make this file beautiful and searchable if this error is corrected: It looks like row 2 should actually have 5 columns, instead of 9. in line 1.
0,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2
1,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2,a value of dataA-3,a value of dataB-3,a value of dataA-4,a value of dataB-4
2,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2
3,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2,a value of dataA-3,a value of dataB-3,a value of dataA-4,a value of dataB-4
4,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2
5,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2,a value of dataA-3,a value of dataB-3,a value of dataA-4,a value of dataB-4
6,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2
7,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2,a value of dataA-3,a value of dataB-3,a value of dataA-4,a value of dataB-4
8,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2
9,a value of dataA-1,a value of dataB-1,a value of dataA-2,a value of dataB-2,a value of dataA-3,a value of dataB-3,a value of dataA-4,a value of dataB-4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment