Last active
April 30, 2021 07:51
-
-
Save runceel/f72668f997d133864cb1df8a9ebc501c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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