将 CsvHelper 自定义转换器应用于特定 class 个地图字段
Apply CsvHelper custom converter to specific class map field(s)
运行 CSVHelper 7.0.0 并尝试添加可应用于特定 class 地图字段的自定义字符串转换器(不想全局应用于所有字符串类型的字段)。以下是我目前如何设置 class 地图、自定义转换器和 csv 编写器调用设置的片段。
Class NextReviewDate 地图字段上带有自定义转换器的地图代码片段:
public sealed class MyCustomClassMap : ClassMap<MyCustomClass>
{
public MyCustomClassMap()
{
Map(m => m.ContentId).Index(0);
Map(m => m.Name).Index(1);
Map(m => m.ContentOwner).Index(2);
Map(m => m.ContentOwnerName).Index(3);
Map(m => m.CopyrightOwner).Index(4);
Map(m => m.CopyrightOwnerName).Index(5);
Map(m => m.NextReviewDate).Index(6).TypeConverter<DateTimeStringConverter>();
Map(m => m.ContentStatus).Index(7);
Map(m => m.UsageRights).Index(8);
Map(m => m.SchemaName).Index(9);
}
}
自定义字符串转换器代码片段:
public class DateTimeStringConverter : StringConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
string formattedDateString = string.Empty;
if (DateTime.TryParse(text, out DateTime dateobj))
{
formattedDateString = dateobj.ToString("MM-dd-yyyy");
}
//throw new Exception("DateTimeStringConverter value: " + formattedDateString);
return formattedDateString;
}
}
我如何注册 class 地图和写入记录的代码片段:
csv.Configuration.RegisterClassMap<MyCustomClassMap>();
csv.WriteRecords(results);
为了排除故障,我在 DateTimeStringConverter 中添加了一个抛出异常,但它似乎从未被调用过。我错过了一块吗?现在,CSV 正在生成并包含原始 NextReviewDate 映射字段值,而无需调用自定义转换器。
编辑:根据@Self 反馈将自定义字符串转换器更改为以下已解决的问题:
public class DateTimeStringConverter : DefaultTypeConverter
{
public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
string strVal = (string)value;
if (DateTime.TryParse(strVal, out DateTime dateobj))
{
strVal = dateobj.ToString("MM-dd-yyyy");
}
return strVal;
}
}
CSV 助手 26.1.0
第一个StringConverter
只提供了一种覆盖object ConvertFromString(..)
的方法。
到字符串的转换没有任何处理,因为它应该是 string
.
这里我假设你的类型是 DateTime
并且你得到的是 multiple Exotique 格式。如果您只有一种格式,您可以更改该类型的默认格式。
一个简单的演示 class 及其映射:
public class Test
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
public DateTime Date { get; set; }
public DateTime Time { get; set; }
}
public sealed class TestMap : ClassMap<Test>
{
public TestMap()
{
AutoMap(CultureInfo.InvariantCulture);
Map(x => x.Date).TypeConverter(new DateStringConverter("MM - dd - yyyy"));
Map(x => x.Time).TypeConverter(new DateStringConverter("mm # hh # ss"));
}
}
我使用了从 ITypeConverter
继承的转换器,以便同时拥有 ConvertFromString
和 ConvertToString
。
具有可自定义的格式、文化和风格。
public class DateStringConverter : ITypeConverter
{
private readonly string _dateFormat;
private readonly CultureInfo _CultureInfo;
private readonly DateTimeStyles _DateTimeStyles;
public DateStringConverter(string dateFormat) :
this(dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None)
{ }
public DateStringConverter(string dateFormat, CultureInfo cultureInfo, DateTimeStyles dateTimeStyles)
{
_dateFormat = dateFormat;
_CultureInfo = cultureInfo;
_DateTimeStyles = dateTimeStyles;
}
public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
string formattedDateString = string.Empty;
if (DateTime.TryParseExact(text, _dateFormat, _CultureInfo, _DateTimeStyles, out DateTime dateObj))
{
return dateObj;
}
return null;
}
public string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
if (value == null) return string.Empty;
if (DateTime.TryParse(value.ToString(), out DateTime dt))
return dt.ToString(_dateFormat);
else
return string.Empty;
}
}
正在编写 CSV:
using (var writer = new StringWriter())
using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture, true))
{
csvWriter.Context.RegisterClassMap<TestMap>();
csvWriter.WriteRecords(datas);
csvWriter.Flush();
csvTextOuput = writer.ToString();
}
结果:
Id,DateTime,Date,Time
1,04/14/2021 09:18:02,04 - 14 - 2021,18 # 09 # 02
2,04/15/2021 09:18:02,04 - 15 - 2021,18 # 09 # 02
3,04/16/2021 12:18:02,04 - 16 - 2021,18 # 12 # 02
正在读取 CSV:
using (var reader = new StringReader(csvTextOuput))
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture, true))
{
csvReader.Context.RegisterClassMap<TestMap>();
ObjectFromCSV = csvReader.GetRecords<Test>().ToArray();
}
结果:
[
{
Date : 04/14/2021
DateTime : 04/14/2021
Id : 1
Time : 04/14/2021
},
{
Date : 04/15/2021
DateTime : 04/15/2021
Id : 2
Time : 04/14/2021
},
{
Date : 04/16/2021
DateTime : 04/16/2021
Id : 3
Time : 04/14/2021
}
]
现场演示https://dotnetfiddle.net/EMdhtn
CSV 助手 7
https://dotnetfiddle.net/5DgwxY
唯一的修改应该是 reader/writer ctor 中没有文化。 RegisterClassMap
从 Configuration
移动到 Context
- ~new CsvReader(reader, CultureInfo.InvariantCulture, true))~ => new CsvReader(reader))
- ~csvWriter.Context.RegisterClassMap()~ => csvWriter.Configuration.RegisterClassMap();
所有 属性.
的同类日期时间格式
如果您在任何地方都使用相同的格式,建议的解决方案:
N.B:TypeConverterFactory
或 TypeConverterCache
旧版本。
运行 CSVHelper 7.0.0 并尝试添加可应用于特定 class 地图字段的自定义字符串转换器(不想全局应用于所有字符串类型的字段)。以下是我目前如何设置 class 地图、自定义转换器和 csv 编写器调用设置的片段。
Class NextReviewDate 地图字段上带有自定义转换器的地图代码片段:
public sealed class MyCustomClassMap : ClassMap<MyCustomClass>
{
public MyCustomClassMap()
{
Map(m => m.ContentId).Index(0);
Map(m => m.Name).Index(1);
Map(m => m.ContentOwner).Index(2);
Map(m => m.ContentOwnerName).Index(3);
Map(m => m.CopyrightOwner).Index(4);
Map(m => m.CopyrightOwnerName).Index(5);
Map(m => m.NextReviewDate).Index(6).TypeConverter<DateTimeStringConverter>();
Map(m => m.ContentStatus).Index(7);
Map(m => m.UsageRights).Index(8);
Map(m => m.SchemaName).Index(9);
}
}
自定义字符串转换器代码片段:
public class DateTimeStringConverter : StringConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
string formattedDateString = string.Empty;
if (DateTime.TryParse(text, out DateTime dateobj))
{
formattedDateString = dateobj.ToString("MM-dd-yyyy");
}
//throw new Exception("DateTimeStringConverter value: " + formattedDateString);
return formattedDateString;
}
}
我如何注册 class 地图和写入记录的代码片段:
csv.Configuration.RegisterClassMap<MyCustomClassMap>();
csv.WriteRecords(results);
为了排除故障,我在 DateTimeStringConverter 中添加了一个抛出异常,但它似乎从未被调用过。我错过了一块吗?现在,CSV 正在生成并包含原始 NextReviewDate 映射字段值,而无需调用自定义转换器。
编辑:根据@Self 反馈将自定义字符串转换器更改为以下已解决的问题:
public class DateTimeStringConverter : DefaultTypeConverter
{
public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
string strVal = (string)value;
if (DateTime.TryParse(strVal, out DateTime dateobj))
{
strVal = dateobj.ToString("MM-dd-yyyy");
}
return strVal;
}
}
CSV 助手 26.1.0
第一个StringConverter
只提供了一种覆盖object ConvertFromString(..)
的方法。
到字符串的转换没有任何处理,因为它应该是 string
.
这里我假设你的类型是 DateTime
并且你得到的是 multiple Exotique 格式。如果您只有一种格式,您可以更改该类型的默认格式。
一个简单的演示 class 及其映射:
public class Test
{
public int Id { get; set; }
public DateTime DateTime { get; set; }
public DateTime Date { get; set; }
public DateTime Time { get; set; }
}
public sealed class TestMap : ClassMap<Test>
{
public TestMap()
{
AutoMap(CultureInfo.InvariantCulture);
Map(x => x.Date).TypeConverter(new DateStringConverter("MM - dd - yyyy"));
Map(x => x.Time).TypeConverter(new DateStringConverter("mm # hh # ss"));
}
}
我使用了从 ITypeConverter
继承的转换器,以便同时拥有 ConvertFromString
和 ConvertToString
。
具有可自定义的格式、文化和风格。
public class DateStringConverter : ITypeConverter
{
private readonly string _dateFormat;
private readonly CultureInfo _CultureInfo;
private readonly DateTimeStyles _DateTimeStyles;
public DateStringConverter(string dateFormat) :
this(dateFormat, CultureInfo.InvariantCulture, DateTimeStyles.None)
{ }
public DateStringConverter(string dateFormat, CultureInfo cultureInfo, DateTimeStyles dateTimeStyles)
{
_dateFormat = dateFormat;
_CultureInfo = cultureInfo;
_DateTimeStyles = dateTimeStyles;
}
public object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
string formattedDateString = string.Empty;
if (DateTime.TryParseExact(text, _dateFormat, _CultureInfo, _DateTimeStyles, out DateTime dateObj))
{
return dateObj;
}
return null;
}
public string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData)
{
if (value == null) return string.Empty;
if (DateTime.TryParse(value.ToString(), out DateTime dt))
return dt.ToString(_dateFormat);
else
return string.Empty;
}
}
正在编写 CSV:
using (var writer = new StringWriter())
using (var csvWriter = new CsvWriter(writer, CultureInfo.InvariantCulture, true))
{
csvWriter.Context.RegisterClassMap<TestMap>();
csvWriter.WriteRecords(datas);
csvWriter.Flush();
csvTextOuput = writer.ToString();
}
结果:
Id,DateTime,Date,Time
1,04/14/2021 09:18:02,04 - 14 - 2021,18 # 09 # 02
2,04/15/2021 09:18:02,04 - 15 - 2021,18 # 09 # 02
3,04/16/2021 12:18:02,04 - 16 - 2021,18 # 12 # 02
正在读取 CSV:
using (var reader = new StringReader(csvTextOuput))
using (var csvReader = new CsvReader(reader, CultureInfo.InvariantCulture, true))
{
csvReader.Context.RegisterClassMap<TestMap>();
ObjectFromCSV = csvReader.GetRecords<Test>().ToArray();
}
结果:
[
{
Date : 04/14/2021
DateTime : 04/14/2021
Id : 1
Time : 04/14/2021
},
{
Date : 04/15/2021
DateTime : 04/15/2021
Id : 2
Time : 04/14/2021
},
{
Date : 04/16/2021
DateTime : 04/16/2021
Id : 3
Time : 04/14/2021
}
]
现场演示https://dotnetfiddle.net/EMdhtn
CSV 助手 7
https://dotnetfiddle.net/5DgwxY
唯一的修改应该是 reader/writer ctor 中没有文化。 RegisterClassMap
从 Configuration
移动到 Context
- ~new CsvReader(reader, CultureInfo.InvariantCulture, true))~ => new CsvReader(reader))
- ~csvWriter.Context.RegisterClassMap()~ => csvWriter.Configuration.RegisterClassMap();
所有 属性.
的同类日期时间格式如果您在任何地方都使用相同的格式,建议的解决方案:
N.B:TypeConverterFactory
或 TypeConverterCache
旧版本。