【问题标题】:Using CsvHelper can I translate white space to a nullable?使用 CsvHelper 可以将空白转换为可为空的吗?
【发布时间】:2012-10-24 21:45:10
【问题描述】:

我有一些非常糟糕的 Csv 文件需要解析。我正在使用 CsvHelper,它工作得很棒。除了我有一些有空格的行,通常我有一个双倍。

文件:

文本,SomeDouble,MoreText

"好",1.23,"好"

“坏”、“坏”

如果我尝试将其映射到

public class Test
{
  [CsvField(Name = "Text")]
  public string Text { get; set; }

  [CsvField(Name = "SomeDouble")]
  public double? SomeDouble{ get; set; }

  [CsvField(Name = "MoreText")]
  public string MoreText{ get; set; }
}

然后我收到这样的错误:

CsvHelper.CsvReaderException:尝试读取 记录类型

行:'2'(从 1 开始)

字段索引:'1'(从 0 开始)

字段名称:'SomeDouble'

字段值:' '

System.Exception: 不是 Double 的有效值。 ---> System.FormatException:输入字符串的格式不正确。
在 System.Number.ParseDouble(字符串值,NumberStyles 选项, NumberFormatInfo numfmt) 在 System.ComponentModel.DoubleConverter.FromString(字符串值, NumberFormatInfo 格式信息)在 System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo 文化, 对象值) --- 内部结束 异常堆栈跟踪 --- 在 System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext 上下文,CultureInfo 文化,对象值)在 System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContext 上下文,CultureInfo 文化,对象值)在 lambda_method(闭包,ICsvReader)在 CsvHelper.CsvReader.d__0`1.MoveNext()

在我看来,我的选择是创建一个自定义解析器,或者将我的值映射到一个字符串属性并在那里进行解析。

还有其他选择吗?

如果我可以配置我想将空白视为空,那就太好了。

根据要求,这里是重现问题的代码示例

 static class Program
    {
        public class Test
        {
            [CsvField(Name = "Text")]
            public string Text { get; set; }

            [CsvField(Name = "SomeDouble")]
            public double? SomeDouble { get; set; }

            [CsvField(Name = "MoreText")]
            public string MoreText { get; set; }
        }

        static void Main(string[] args)
        {
            // create fake in memory file
            var memoryStream = new MemoryStream();
            var streamWriter = new StreamWriter(memoryStream);
            streamWriter.WriteLine("Text,SomeDouble,MoreText");
            streamWriter.WriteLine("Good, 1.23, Good");
            streamWriter.WriteLine("Bad, ,Bad");

            streamWriter.Flush();

            //reset the file to the begining
            memoryStream.Position = 0;

            using (
                var csv =
                    new CsvReader(
                        new StreamReader(memoryStream)))
            {
                // this call will blow up with the exception.
                var records = csv.GetRecords<Test>().ToList();

                //carry on and do stuff with 'records'...
            }
    }

谢谢。

【问题讨论】:

  • 您能否发布实际失败的方法的代码,我对 CSVHelper 不熟悉。
  • 我用一个更好的例子编辑了这个问题
  • 我不认为它可以做到这一点,但这有帮助吗:custom typeconverter 我要看看我是否可以使用它,我可以使用该功能也。如果您找到解决方案,请发布。

标签: c# .net parsing csv csvhelper


【解决方案1】:

最后,我创建了自己的类型转换器,它将空白视为 null。

public class WhiteSpaceToNullableTypeConverter<T> : TypeConverter where T : struct
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof (string);
    }

    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        return destinationType == typeof (T?);
    }

    public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture,
                                       object value)
    {
        T? result = null;

        var stringValue = (string) value;
        if (!string.IsNullOrWhiteSpace(stringValue))
        {
            var converter = TypeDescriptor.GetConverter(typeof(T));
            result = (T)converter.ConvertFrom(stringValue.Trim());
        }

        return result;
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture,
                                     object value, Type destinationType)
    {
        var result = (T?) value;
        return result.ToString();
    }
}

像这样将它应用到您的模型中

public class Test
{
    [CsvField(Name = "Text")]
    public string Text { get; set; }

    [CsvField(Name = "SomeDouble")]
    [TypeConverter( typeof( WhiteSpaceToNullableTypeConverter<Double> ) )]
    public double? SomeDouble{ get; set; }

    [CsvField(Name = "MoreText")]
    public string MoreText{ get; set; }
}

【讨论】:

    【解决方案2】:

    一个简单的方法是在你的ClassMap 中使用ConvertUsing()

    Map(x => x.SomeDouble)
        .ConvertUsing(row => 
            string.IsNullOrWhiteSpace(row.GetField("SomeDouble")) ?
                (double?) null : 
                Convert.ToDouble(row.GetField("SomeDouble")));
    

    我喜欢制作一些小辅助函数并调用它们

    Map(x => x.SomeDouble)
        .ConvertUsing(row => GetOddballDouble(row.GetField("SomeDouble")));
    

    【讨论】:

      猜你喜欢
      • 2014-10-20
      • 1970-01-01
      • 1970-01-01
      • 2017-03-07
      • 1970-01-01
      • 2012-11-03
      • 1970-01-01
      • 1970-01-01
      • 2021-02-03
      相关资源
      最近更新 更多