mperdeck/LINQtoCSV

Parsing nullable decimal fails

Opened this issue · 1 comments

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 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 );
            }
        }