'Trying to implement a type converter for CsvHelper has no effect

I am trying to globally register a CsvHelper type converter that handles the value NULL for a decimal?, but when I do the registration is ignored and the converter is not invoked. Not sure what else to do.

My converter:

public class NullDecimalConverter : DecimalConverter
{
    public override object ConvertFromString(string text, IReaderRow row, MemberMapData mapData)
    {
        if (text == "NULL") return null;
        return base.ConvertFromString(text, row, mapData);
    }
}

My class and mapping are as follows:

public class Model
{
    public decimal? Score{ get; set; }      
}

public class ScoreMapping : ClassMap<Model>
{
    public ScoreMapping()
    {
        Map(m => m.Score).Name("sub_score");
    }
}

And to set it up

csvReader.Context.RegisterClassMap<ScoreMapping>();
csvReader.Context.TypeConverterCache.AddConverter<decimal>(new NullDecimalConverter());
var records = csvReader.GetRecords<Model>().ToList();

But the library doesn't do it

CsvHelper.TypeConversion.TypeConverterException : The conversion cannot be performed.
    Text: 'NULL'
    MemberType: System.Nullable`1[[System.Decimal, System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]]
    TypeConverter: 'CsvHelper.TypeConversion.NullableConverter'

Demo fiddle here.


As a workaround, it seems I can add the TypeConverter on each type, but this is clunky, is there a proper way to register the type converter globally?

Map(m => m.Score).Name("sub_score").TypeConverter<NullDecimalConverter>();


Solution 1:[1]

The issue here was order of execution... AddConverter must be called before RegisterClassMap else the converter will not be registered.

I reckon I should raise this as a bug because relying on order is probably something to avoid, especially in a library where this could easily be overlooked.

    // fails because class map is registered first
    csv.Context.RegisterClassMap<ScoreMapping>();
    csv.Context.TypeConverterCache.AddConverter<decimal>(new NullDecimalConverter());

    // works because TypeConverter is added first
    csv.Context.TypeConverterCache.AddConverter<decimal>(new NullDecimalConverter());
    csv.Context.RegisterClassMap<ScoreMapping>();

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 PandaWood