LINQtoCSV
LINQtoCSV copied to clipboard
Parsing nullable decimal fails
Parsing a field declared as decimal? fails with a FormatException with the value "2,000,000".
This is caused because when the TypeFieldInfo class (inside FieldMapper<T> class) sets up the converters it uses the fields PropertyType or FieldType to determine if that type has a Parse or ParseExact method (FieldMapper.cs lines 96-114). If it doesn't it falls back to a type converter. Unfortunately the type converter hard codes NumberStyles.Float (DecimalConverter.FromString(string, NumberFormatInfo) which won't parse decimal strings with a comma as a thousands seperator.
To fix the field type should be checked for nullable, and if it is to use the underlying type to test for a Parse or ParseExact method.
The only work around as it currently stands is to change the type of the field from decimal? to decimal and use the CanBeNull=true attribute.
@chrispday I haven't done an official pull request yet, but I ran into the same problem today. I put together a quick bit of code to fix it; you're welcome to use it as-is or improve it if needed. I have not done full testing on it, but it is covering my needs so far. Hope this can help!
In FieldMapper.cs, I went to the AnalyzeTypeField method and entered the following block, replacing the section of code between the //parseNumberMethod comment block and the //Process the attributes comment block.
var type = tfi.fieldType;
var isNullable = type.IsGenericType && type.GetGenericTypeDefinition( ) == typeof( Nullable<> );
if ( isNullable )
type = type.GetGenericArguments( )[0];
tfi.parseNumberMethod =
type.GetMethod( "Parse",
new Type[] { typeof( String ), typeof( NumberStyles ), typeof( IFormatProvider ) } );
if ( tfi.parseNumberMethod == null )
{
if ( m_fileDescription.UseOutputFormatForParsingCsvValue )
{
tfi.parseExactMethod = type.GetMethod( "ParseExact",
new Type[] { typeof( string ), typeof( string ), typeof( IFormatProvider ) } );
}
tfi.typeConverter = null;
if ( tfi.parseExactMethod == null )
{
tfi.typeConverter =
TypeDescriptor.GetConverter( type );
}
}