CsvHelper 将映射器一 属性 写入多列
CsvHelper write mapper one property to multiple columns
我正在使用 csvHelper(版本 2.8.4)将 class 写入 csv。
我的 class 看起来像这样:
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict{ get; set; }
}
是否可以编写将 Dict
属性 映射到多列的映射器?使用某种转换器?
例如,如果 class 具有以下值:
数量 = 15
Dict = new Dictionary{["a1"] = "a2",["b1"] = "b2"}
我希望生成的 csv 为:
Amount,a1,b1
15,a2,b2
谢谢!
如链接问题中所述,您可以使用 ExpandoObject
来序列化字典。
以下代码仅适用于写入 CSV,它在序列化期间将 classA
对象转换为 ExpandoObject
,包括手动添加的 Amount
属性。
public static List<dynamic> ToExpandoObjects(IReadOnlyList<classA> aObjects)
{
var allKeys = aObjects
.SelectMany(a => a.Dict.Keys)
.Distinct()
.ToHashSet();
var result = new List<dynamic>();
foreach (var a in aObjects)
{
var asExpando = new ExpandoObject();
var asDictionary = (IDictionary<string, object>)asExpando;
asDictionary[nameof(classA.Amount)] = a.Amount;
foreach (var key in allKeys)
{
if(a.Dict.TryGetValue(key, out var value))
asDictionary[key] = value;
else
asDictionary[key] = null;
}
result.Add(asExpando);
}
return result;
}
...
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
例如称为:
var records = new[] {
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
},
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["c1"] = "c2",["b1"] = "b2"}
}
};
StringBuilder sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
Console.WriteLine(sb.ToString());
生产
Amount
a1
b1
c1
15
a2
b2
15
b2
c2
可能最简单的方法是手动写出字典部分。
*** 更新以使用 CsvHelper 版本 2.8.4 ***
void Main()
{
var records = new List<classA>
{
new classA {
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
}
};
using (var csv = new CsvWriter(Console.Out))
{
var dict = records.First().Dict;
var properties = typeof(classA).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.Name);
}
}
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.GetValue(record));
}
}
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
// You can define other methods, fields, classes and namespaces here
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
*** 适用于当前版本 27.2.1 ***
void Main()
{
var records = new List<classA>
{
new classA { Amount = 15, Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"} },
};
using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
{
var dict = records.First().Dict;
csv.WriteHeader<classA>();
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
csv.WriteRecord(record);
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
我正在使用 csvHelper(版本 2.8.4)将 class 写入 csv。 我的 class 看起来像这样:
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict{ get; set; }
}
是否可以编写将 Dict
属性 映射到多列的映射器?使用某种转换器?
例如,如果 class 具有以下值:
数量 = 15
Dict = new Dictionary
我希望生成的 csv 为:
Amount,a1,b1
15,a2,b2
谢谢!
如链接问题中所述,您可以使用 ExpandoObject
来序列化字典。
以下代码仅适用于写入 CSV,它在序列化期间将 classA
对象转换为 ExpandoObject
,包括手动添加的 Amount
属性。
public static List<dynamic> ToExpandoObjects(IReadOnlyList<classA> aObjects)
{
var allKeys = aObjects
.SelectMany(a => a.Dict.Keys)
.Distinct()
.ToHashSet();
var result = new List<dynamic>();
foreach (var a in aObjects)
{
var asExpando = new ExpandoObject();
var asDictionary = (IDictionary<string, object>)asExpando;
asDictionary[nameof(classA.Amount)] = a.Amount;
foreach (var key in allKeys)
{
if(a.Dict.TryGetValue(key, out var value))
asDictionary[key] = value;
else
asDictionary[key] = null;
}
result.Add(asExpando);
}
return result;
}
...
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
例如称为:
var records = new[] {
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
},
new classA
{
Amount = 15,
Dict = new Dictionary<string,string>{["c1"] = "c2",["b1"] = "b2"}
}
};
StringBuilder sb = new StringBuilder();
using (var writer = new StringWriter(sb))
using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv.WriteRecords(ToExpandoObjects(records));
}
Console.WriteLine(sb.ToString());
生产
Amount | a1 | b1 | c1 |
---|---|---|---|
15 | a2 | b2 | |
15 | b2 | c2 |
可能最简单的方法是手动写出字典部分。
*** 更新以使用 CsvHelper 版本 2.8.4 ***
void Main()
{
var records = new List<classA>
{
new classA {
Amount = 15,
Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"}
}
};
using (var csv = new CsvWriter(Console.Out))
{
var dict = records.First().Dict;
var properties = typeof(classA).GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.Name);
}
}
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
foreach (PropertyInfo property in properties)
{
if (property.Name != "Dict")
{
csv.WriteField(property.GetValue(record));
}
}
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
// You can define other methods, fields, classes and namespaces here
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}
*** 适用于当前版本 27.2.1 ***
void Main()
{
var records = new List<classA>
{
new classA { Amount = 15, Dict = new Dictionary<string,string>{["a1"] = "a2",["b1"] = "b2"} },
};
using (var csv = new CsvWriter(Console.Out, CultureInfo.InvariantCulture))
{
var dict = records.First().Dict;
csv.WriteHeader<classA>();
foreach (var item in dict)
{
csv.WriteField(item.Key);
}
csv.NextRecord();
foreach (var record in records)
{
csv.WriteRecord(record);
foreach (var item in record.Dict)
{
csv.WriteField(item.Value);
}
csv.NextRecord();
}
}
}
public class classA
{
public int Amount { get; set; }
public Dictionary<string, string> Dict { get; set; }
}