最近遇到了相同的问题,为了完整起见,再发布另一个答案。我们有一个相当复杂的类似于ClassMap<Worker>
的类,不想失去它。此外,我们需要进行CSV写入和读取,因此需要来自robs答案的ExpandoObject
。最终,这种方法是Michael Richardson和robs答案的结合,应该带来两者之间的最佳效果。
此外,在读取CSV文件期间区分字典字段的好方法是在它们的前缀中加上像"customerField."
这样的东西。
首先,我们需要将字典转换为/from Worker.customerField:
public static class WorkerExtensions
{
const string CustomerFieldPrefix = nameof(Worker.customerField) + ".";
public static dynamic GetCustomerFieldExpando(this Worker worker)
{
var expando = new ExpandoObject() as IDictionary<string, object>;
foreach (var fieldPair in worker.customerField)
{
expando[CustomerFieldPrefix + fieldPair.Key] = fieldPair.Value ?? "";
}
return expando;
}
public static void SetCustomerField(this Worker worker, ExpandoObject expando)
{
var columnsToValues = expando as IDictionary<string, object>;
foreach (var columnValuePair in columnsToValues)
{
if (columnValuePair.Key.StartsWith(CustomerFieldPrefix)
&& columnValuePair.Key.Length > CustomerFieldPrefix.Length)
{
string key = columnValuePair.Key.Substring(CustomerFieldPrefix.Length);
worker.customerField[key] = columnValuePair.Value;
}
}
}
}
接下来,CSV写入可以使用
ClassMap
和
ExpandoObject
,代码如下:
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.RegisterClassMap<WorkerMap>();
csv.WriteHeader<Worker>();
(workers.First().GetCustomerFieldExpando() as IDictionary<string, object>)
.Keys.ToList().ForEach(key => csv.WriteField(key));
csv.NextRecord();
foreach (var worker in workers)
最后,CSV读取也可以同时结合ClassMap
和ExpandoObject
使用:
List<Worker> workers = new List<Worker>();
csv.Configuration.HasHeaderRecord = true;
csv.Configuration.RegisterClassMap<WorkerMap>();
csv.Read();
csv.ReadHeader();
var columns = csv.Context.HeaderRecord;
while (csv.Read())
在读取CSV时,如果你想要将真实类型读入字典值中(而不仅仅是字符串),情况会变得更加复杂。为了能够从
ExpandoObject
转换为正确的类型,我们需要预定义字典键和数据类型之间的关联。