12

我想知道 Josh Close 的 CsvHelper 是否在我缺少的配置中有任何东西可以将值转换为 null。我是这个库的忠实粉丝,但我一直认为应该有某种配置让它知道你的文件中哪些值代表 NULL。一个示例是具有值“NA”、“EMPTY”、“NULL”等的列。我确信我可以创建自己的 TypeConverter,但我希望有一个更简单的选项可以在配置中的某个位置设置为这在我遇到的文件中很常见。

是否有一个配置设置可以相对容易地做到这一点?

我在 CsvHelper.TypeConversion 命名空间中找到了 TypeConversion,但不确定在哪里应用这样的东西或正确用法的示例:

new NullableConverter(typeof(string)).ConvertFromString(new TypeConverterOptions(), "NA")

我也在使用最新版本 2.2.2

谢谢!

4

3 回答 3

22

我认为在过去七年和十三个版本中的某个时间,因为这个问题被问到在没有扩展自定义类型映射类的情况下执行此操作的选项,例如:

csvReader.Context.TypeConverterOptionsCache.GetOptions<string>().NullValues.Add("NULL");
csvReader.Context.TypeConverterOptionsCache.GetOptions<DateTime?>().NullValues.AddRange(new[] { "NULL", "0" });
csvReader.Context.TypeConverterOptionsCache.GetOptions<int?>().NullValues.Add("NULL");
csvReader.Context.TypeConverterOptionsCache.GetOptions<bool>().BooleanFalseValues.Add("0");
csvReader.Context.TypeConverterOptionsCache.GetOptions<bool>().BooleanTrueValues.Add("1");
于 2020-02-10T21:10:10.717 回答
15

CsvHelper 绝对可以处理可为空的类型。如果空白列被视为空,则不需要滚动自己的 TypeConverter。对于我的示例,我假设您使用的是用户定义的流畅映射。

您需要做的第一件事是CsvHelper.TypeConverter为您的 Nullable 类型构造一个对象。请注意,我将使用int默认情况下字符串允许空值。

public class MyClassMap : CsvClassMap<MyClass>
{
     public override CreateMap()
     {
          CsvHelper.TypeConversion.NullableConverter intNullableConverter = new CsvHelper.TypeConversion.NullableConverter(typeof(int?));

          Map(m => m.number).Index(2).TypeConverter(intNullableConverter);
      }
 }

接下来是在您的 CsvReader 对象上设置属性以允许空白列和自动修剪您的字段。CsvConfiguration个人喜欢通过在构建对象之前使用我的所有设置创建一个对象来做到这一点CsvReader

CsvConfiguration csvConfig = new CsvConfiguration();
csvConfig.RegisterClassMap<MyClassMap>();
csvConfig.WillThrowOnMissingField = false;
csvConfig.TrimFields = true;

然后你可以调用myReader = new CsvReader(stream, csvConfig)来构建CsvReader对象。

如果您需要为 null 定义值,"NA" == null那么您将需要推出自己的CsvHelper.TypeConversion课程。我建议您扩展NullableConverter类来执行此操作并覆盖构造函数和ConvertFromString方法。不过,使用空白值作为 null 确实是您最好的选择。

于 2013-10-07T17:10:11.340 回答
3

我使用“ConvertUsing”...

public class RecordMap : CsvHelper.Configuration.ClassMap<Record>
{
    public RecordMap()
    {
        AutoMap();
        Map(m => m.TransactionDate).ConvertUsing( NullDateTimeParser );
        Map(m => m.DepositDate).ConvertUsing( NullDateTimeParser );
    }

    public DateTime? NullDateTimeParser(IReaderRow row)
    {
        //"CurrentIndex" is a bit of a misnomer here - it's the index of the LAST GetField call so we need to +1
        //https://github.com/JoshClose/CsvHelper/issues/1168

        var rawValue = row.GetField(row.Context.CurrentIndex+1);

        if (rawValue == "NULL")
            return null;
        else
            return DateTime.Parse(rawValue);

    }
}
于 2019-05-23T17:12:15.863 回答