我目前正在尝试从 csv 文件中解析一个布尔值。我们注意到该值将成功解析
Yes
和 Y
(在任何情况下),但不会解析 No
和 N
我正在像这样映射类映射中的值:
Map(m => m.Enabled).Name("Enabled").TypeConverterOption(false, string.Empty);
是否有原因导致它会读为
Yes
而不是 No
?有没有办法添加解析 no
的能力?
在 4.0.3 版本中,此功能有效。
void Main()
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader))
{
writer.WriteLine("Id,Name,IsSomething");
writer.WriteLine("1,one,Yes");
writer.WriteLine("2,two,Y");
writer.WriteLine("3,three,No");
writer.WriteLine("4,four,N");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<TestMap>();
csv.GetRecords<Test>().ToList().Dump();
}
}
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSomething { get; set; }
}
public sealed class TestMap : ClassMap<Test>
{
public TestMap()
{
Map(m => m.Id);
Map(m => m.Name);
Map(m => m.IsSomething)
.TypeConverterOption.BooleanValues(true, true, "Yes", "Y")
.TypeConverterOption.BooleanValues(false, true, "No", "N");
}
}
在 2.16.3 版本中,此功能有效。
void Main()
{
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
using (var reader = new StreamReader(stream))
using (var csv = new CsvReader(reader))
{
writer.WriteLine("Id,Name,IsSomething");
writer.WriteLine("1,one,Yes");
writer.WriteLine("2,two,Y");
writer.WriteLine("3,three,No");
writer.WriteLine("4,four,N");
writer.Flush();
stream.Position = 0;
csv.Configuration.RegisterClassMap<TestMap>();
csv.GetRecords<Test>().ToList().Dump();
}
}
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsSomething { get; set; }
}
public sealed class TestMap : CsvClassMap<Test>
{
public TestMap()
{
Map(m => m.Id);
Map(m => m.Name);
Map(m => m.IsSomething)
.TypeConverterOption(true, "Yes", "Y")
.TypeConverterOption(false, "No", "N");
}
}
作为扩展方法,让使用更简单。
Map(x => x.IsActive).Name("Active").WithExtendedBooleanValues();
在 v15 上进行了测试,但我确信在此之前它可以正常工作。
namespace CsvHelper.Configuration
{
public static class MemberMapExtensions
{
/// <summary>
/// Adds "y", "yes" and "set to yes" and the "no" equivalents to the list of accepted boolean values
/// for this member map.
/// </summary>
public static MemberMap<TClass, TMember> WithExtendedBooleanValues<TClass, TMember>(
this MemberMap<TClass, TMember> memberMap)
{
memberMap
// Note: It's case insensitive
// https://github.com/JoshClose/CsvHelper/blob/master/src/CsvHelper/TypeConversion/BooleanConverter.cs
.TypeConverterOption.BooleanValues(true, clearValues: false, "y", "yes", "set to yes")
.TypeConverterOption.BooleanValues(false, clearValues: false, "n", "no", "set to no");
return memberMap;
}
}
}
我们在版本 7 中使用以下内容
单个映射的用法:
Map(m => m.IsSomething).Name("IsSomething").TypeConverter<MyBooleanConverter>();
申请CSV阅读器的用途
csv.Configuration.TypeConverterCache.AddConverter<bool>(new MyBooleanConverter());
代码:
public sealed class MyBooleanConverter : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if(TryParseConvertBoolean(text, out bool result))
{
return result;
}
return null;
}
public static bool TryParseConvertBoolean(string value, out bool result)
{
result = false;
try
{
if (string.IsNullOrWhiteSpace(value))
return false;
else
{
var lower = value.ToLower();
if (lower == "no" || lower == "n")
{
result = false;
return true;
}
else if (lower == "yes" || lower == "y")
{
result = true;
return true;
}
}
}
catch { }
return false;
}
}
上面的答案有一个错误,这是我正在使用的简化版本,效果很好:
public sealed class MyBooleanConverter : DefaultTypeConverter
{
public override object ConvertFromString(string text, IReaderRow row, MemberMapData memberMapData)
{
if (string.IsNullOrWhiteSpace(text)) return false;
var lower = text.ToLower();
if (lower == "yes" || lower == "y" || lower == "1") return true;
return false;
}
}