使用CsvHelper可以将空格转换为可空吗?

我有一些非常蹩脚的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.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,Object value)的System.ComponentModel.DoubleConverter.FromString(String value,NumberFormatInfo formatInfo)中的System.Number.ParseDouble(String value,NumberStyles options,NumberFormatInfo numfmt) – – 内部exception堆栈跟踪的结束—在lambda_method处的System.ComponentModel.BaseNumberConverter.ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,Object value)处于System.ComponentModel.NullableConverter.ConvertFrom(ITypeDescriptorContext context,CultureInfo culture,Object value)处(闭包,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().ToList(); //carry on and do stuff with 'records'... } } 

谢谢。

最后,我创建了自己的类型转换器,将空白与null相同。

 public class WhiteSpaceToNullableTypeConverter : 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 ) )] public double? SomeDouble{ get; set; } [CsvField(Name = "MoreText")] public string MoreText{ get; set; } } 

一种简单的方法是在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")));