如何将 EnumConverter 与 CsvHelper 一起使用
How to use EnumConverter with CsvHelper
我正在使用 CsvHelper 将 class 序列化为 csv 文件 - 在此之前一切正常。
现在我正在尝试找到一种方法将 class 的枚举属性转换为它们在 csv 中的 int 值,这样我以后就可以使用 CSV 进行批量插入。
我在 CsvHelper 中找到了 EnumConverter class,但我不知道如何正确使用它,因为我的所有尝试都失败了。
这是我的映射class代码
public sealed class MyMapping : CsvClassMap<TradingCalendarException>
{
public MyMapping()
{
EnumConverter enumConverter = new EnumConverter(typeof(CalendarExceptionEntityType));
Map(m => m.ExceptionEntityType).Index(0).Name("EXCEPTION_ENTITY_TYPE").TypeConverter(enumConverter);
Map(m => m.ExceptionEntityIdentifier).Index(1).Name("EXCEPTION_ENTITY_IDENTIFIER");
Map(m => m.OptionType).Index(2).Name("OPTION_TYPE");
Map(m => m.StartDatetime).Index(3).Name("EXCEPTION_START_DATETIME");
Map(m => m.EndDatetime).Index(4).Name("EXCEPTION_END_DATETIME");
Map(m => m.DataSourceType).Index(5).Name("DATA_SOURCE_TYPE");
Map(m => m.Description).Index(6).Name("DESCRIPTION");
}
}
和写作部分
using (StreamWriter file = new StreamWriter(filePath, false, Encoding.UTF8))
{
CsvWriter writer = new CsvWriter(file);
MyMapping mapping = new MyMapping();
writer.Configuration.RegisterClassMap(mapping);
writer.WriteRecords(calendarExceptionList);
}
映射的其余部分(索引和命名)正在工作,只是 EnumConverter 没有做任何更改。
我没有在网上找到任何示例。
谢谢!
向您的 TradingCalendarException
class 添加一个 int
属性 来回转换到您的自定义枚举,CalendarExceptionEntityType
,例如:
public int ExceptionEntityTypeInt {
get { return (int)ExceptionEntityType; }
set { ExceptionEntityType = (CalendarExceptionEntityType)value; }
}
使用 Map(m => m.ExceptionEntityTypeInt).Index(0).Name("EXCEPTION_ENTITY_TYPE_INT")
而不是枚举转换器 Map(m => m.ExceptionEntityType).Index(0).Name("EXCEPTION_ENTITY_TYPE").TypeConverter(new MyMapping())
这是我做的解决方案:
public class CalendarExceptionEnumConverter<T> : DefaultTypeConverter where T : struct
{
public override string ConvertToString(TypeConverterOptions options, object value)
{
T result;
if(Enum.TryParse<T>(value.ToString(),out result))
{
return (Convert.ToInt32(result)).ToString();
}
throw new InvalidCastException(String.Format("Invalid value to EnumConverter. Type: {0} Value: {1}",typeof(T),value));
}
}
并按如下方式使用:
Map(m => m.ExceptionEntityType).TypeConverter<CalendarExceptionEnumConverter<CalendarExceptionEntityType>>();
我使用了 Yarimi 的解决方案,但发现它无法从 .csv 中读取枚举值(可以写入)
我的解决方案是 class 从 EnumTypeConverter 扩展,而不是 DefaultTypeConverter。
这里是完整的代码
public class OurEnumConverter<T> : CsvHelper.TypeConversion.EnumConverter where T : struct
{
public OurEnumConverter(): base(typeof(T))
{ }
public override string ConvertToString(CsvHelper.TypeConversion.TypeConverterOptions options, object value)
{
T result;
if (Enum.TryParse<T>(value.ToString(), out result))
{
return (Convert.ToInt32(result)).ToString();
}
return base.ConvertToString(options, value);
//throw new InvalidCastException(String.Format("Invalid value to EnumConverter. Type: {0} Value: {1}", typeof (T), value));
}
public override object ConvertFromString(TypeConverterOptions options, string text)
{
int parsedValue;
//System.Diagnostics.Debug.WriteLine($"{typeof(T).Name} = {text}");
if (Int32.TryParse(text, out parsedValue))
{
return (T)(object)parsedValue;
}
return base.ConvertFromString(options, text);
//throw new InvalidCastException(String.Format("Invalid value to EnumConverter. Type: {0} Value: {1}", typeof(T), text));
}
}
这是它的用法
public class TickTradeClassMap : CsvHelper.Configuration.CsvClassMap<TickData.TickTrade>
{
public TickTradeClassMap()
{
Map(m => m.price);
Map(m => m.size);
Map(m => m.exchange).TypeConverter<OurEnumConverter<ATExchangeEnum>>();
Map(m => m.condition1).TypeConverter<OurEnumConverter<ATTradeConditionEnum>>();
}
}
这就是我为 CSV Helper
的最新版本所做的,即 7.1.1
:
public class AggregateEnumConverter<T> : EnumConverter where T : struct
{
public AggregateEnumConverter() : base(typeof(T)) { }
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if(!Enum.TryParse(text, out AggregateType aggregateType))
{
// This is just to make the user life simpler...
if(text == "24HAVG")
{
return AggregateType._24HAVG;
}
// If an invalid value is found in the CSV for the Aggregate column, throw an exception...
throw new InvalidCastException($"Invalid value to EnumConverter. Type: {typeof(T)} Value: {text}");
}
return aggregateType;
}
}
注意:上面的代码使用了 C# 7 新的内联输出变量。
更多信息在这里:How should I convert a string to an enum in C#?
这就是您如何使用自定义 EnumConverter
:
/// <summary>
/// Maps Tag class properties to the CSV columns' names
/// </summary>
public sealed class TagMap : ClassMap<Tag>
{
public TagMap(ILogger<CsvImporter> logger)
{
Map(tag => tag.Aggregate).Name("aggregate").TypeConverter<AggregateEnumConverter<AggregateType>>();
}
}
我正在使用 CsvHelper 将 class 序列化为 csv 文件 - 在此之前一切正常。
现在我正在尝试找到一种方法将 class 的枚举属性转换为它们在 csv 中的 int 值,这样我以后就可以使用 CSV 进行批量插入。
我在 CsvHelper 中找到了 EnumConverter class,但我不知道如何正确使用它,因为我的所有尝试都失败了。
这是我的映射class代码
public sealed class MyMapping : CsvClassMap<TradingCalendarException>
{
public MyMapping()
{
EnumConverter enumConverter = new EnumConverter(typeof(CalendarExceptionEntityType));
Map(m => m.ExceptionEntityType).Index(0).Name("EXCEPTION_ENTITY_TYPE").TypeConverter(enumConverter);
Map(m => m.ExceptionEntityIdentifier).Index(1).Name("EXCEPTION_ENTITY_IDENTIFIER");
Map(m => m.OptionType).Index(2).Name("OPTION_TYPE");
Map(m => m.StartDatetime).Index(3).Name("EXCEPTION_START_DATETIME");
Map(m => m.EndDatetime).Index(4).Name("EXCEPTION_END_DATETIME");
Map(m => m.DataSourceType).Index(5).Name("DATA_SOURCE_TYPE");
Map(m => m.Description).Index(6).Name("DESCRIPTION");
}
}
和写作部分
using (StreamWriter file = new StreamWriter(filePath, false, Encoding.UTF8))
{
CsvWriter writer = new CsvWriter(file);
MyMapping mapping = new MyMapping();
writer.Configuration.RegisterClassMap(mapping);
writer.WriteRecords(calendarExceptionList);
}
映射的其余部分(索引和命名)正在工作,只是 EnumConverter 没有做任何更改。
我没有在网上找到任何示例。
谢谢!
向您的 TradingCalendarException
class 添加一个 int
属性 来回转换到您的自定义枚举,CalendarExceptionEntityType
,例如:
public int ExceptionEntityTypeInt {
get { return (int)ExceptionEntityType; }
set { ExceptionEntityType = (CalendarExceptionEntityType)value; }
}
使用 Map(m => m.ExceptionEntityTypeInt).Index(0).Name("EXCEPTION_ENTITY_TYPE_INT")
而不是枚举转换器 Map(m => m.ExceptionEntityType).Index(0).Name("EXCEPTION_ENTITY_TYPE").TypeConverter(new MyMapping())
这是我做的解决方案:
public class CalendarExceptionEnumConverter<T> : DefaultTypeConverter where T : struct
{
public override string ConvertToString(TypeConverterOptions options, object value)
{
T result;
if(Enum.TryParse<T>(value.ToString(),out result))
{
return (Convert.ToInt32(result)).ToString();
}
throw new InvalidCastException(String.Format("Invalid value to EnumConverter. Type: {0} Value: {1}",typeof(T),value));
}
}
并按如下方式使用:
Map(m => m.ExceptionEntityType).TypeConverter<CalendarExceptionEnumConverter<CalendarExceptionEntityType>>();
我使用了 Yarimi 的解决方案,但发现它无法从 .csv 中读取枚举值(可以写入)
我的解决方案是 class 从 EnumTypeConverter 扩展,而不是 DefaultTypeConverter。
这里是完整的代码
public class OurEnumConverter<T> : CsvHelper.TypeConversion.EnumConverter where T : struct
{
public OurEnumConverter(): base(typeof(T))
{ }
public override string ConvertToString(CsvHelper.TypeConversion.TypeConverterOptions options, object value)
{
T result;
if (Enum.TryParse<T>(value.ToString(), out result))
{
return (Convert.ToInt32(result)).ToString();
}
return base.ConvertToString(options, value);
//throw new InvalidCastException(String.Format("Invalid value to EnumConverter. Type: {0} Value: {1}", typeof (T), value));
}
public override object ConvertFromString(TypeConverterOptions options, string text)
{
int parsedValue;
//System.Diagnostics.Debug.WriteLine($"{typeof(T).Name} = {text}");
if (Int32.TryParse(text, out parsedValue))
{
return (T)(object)parsedValue;
}
return base.ConvertFromString(options, text);
//throw new InvalidCastException(String.Format("Invalid value to EnumConverter. Type: {0} Value: {1}", typeof(T), text));
}
}
这是它的用法
public class TickTradeClassMap : CsvHelper.Configuration.CsvClassMap<TickData.TickTrade>
{
public TickTradeClassMap()
{
Map(m => m.price);
Map(m => m.size);
Map(m => m.exchange).TypeConverter<OurEnumConverter<ATExchangeEnum>>();
Map(m => m.condition1).TypeConverter<OurEnumConverter<ATTradeConditionEnum>>();
}
}
这就是我为 CSV Helper
的最新版本所做的,即 7.1.1
:
public class AggregateEnumConverter<T> : EnumConverter where T : struct
{
public AggregateEnumConverter() : base(typeof(T)) { }
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if(!Enum.TryParse(text, out AggregateType aggregateType))
{
// This is just to make the user life simpler...
if(text == "24HAVG")
{
return AggregateType._24HAVG;
}
// If an invalid value is found in the CSV for the Aggregate column, throw an exception...
throw new InvalidCastException($"Invalid value to EnumConverter. Type: {typeof(T)} Value: {text}");
}
return aggregateType;
}
}
注意:上面的代码使用了 C# 7 新的内联输出变量。
更多信息在这里:How should I convert a string to an enum in C#?
这就是您如何使用自定义 EnumConverter
:
/// <summary>
/// Maps Tag class properties to the CSV columns' names
/// </summary>
public sealed class TagMap : ClassMap<Tag>
{
public TagMap(ILogger<CsvImporter> logger)
{
Map(tag => tag.Aggregate).Name("aggregate").TypeConverter<AggregateEnumConverter<AggregateType>>();
}
}