CsvHelper icon indicating copy to clipboard operation
CsvHelper copied to clipboard

### Registering Class Map once.

Open UnnecessaryPunctuation opened this issue 3 years ago • 1 comments

Registering Class Map once.

I would like to register class Map and the Configuration only once. In order too make sure that future usage of a parser will always use the up to date configuration.

For that I use a class to store everything related to the configuration :

public sealed class CustomerXY_Configuration 
{
    public static CsvConfiguration CsvConfiguration { get; private set; }
    public static CsvContext CsvContext { get; private set; }

    static CustomerXY_Configuration()
    {
        // Configuration
        CsvConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture) { 
                                Delimiter = ";",
                                // etc.. 
                            };
        // Context
        CsvContext = new CsvContext(CsvConfiguration);
        CsvContext.RegisterClassMap<MainClass>();
        CsvContext.RegisterClassMap<SubClassA>();
        CsvContext.RegisterClassMap<SubClassB>();

        // Type Converter
        CsvContext.TypeConverterCache.AddConverter<bool>(new MonoGramme_BoolConverter());

        var dateTimeFormat = new TypeConverterOptions { Formats = new[] { "yyyyMMdd" } };
        CsvContext.TypeConverterOptionsCache.AddOptions<DateTime>(dateTimeFormat);
        CsvContext.TypeConverterOptionsCache.AddOptions<DateTime?>(dateTimeFormat);
    }
}

In the 20.0 version class map and type converter, were in the CsvConfiguration that we could pass to the constructor. But now the Context is read only. public virtual CsvContext Context { get; }

While I can work around that : . Have the configuration class return a new instance of CSV Reader. But this will require overload for every Reader Ctor. . Have a Method that accept an instance of CsvReader / Writer. But I will still have the CsvContext instance, as I like to peak at the configuration in Debug and Log. And as having a context doesn't comme from an interface I have to have different method for each.

public static CsvReader ConfigureReader(CsvReader reader)
{    
    reader.TypeConverterCache.AddConverter<bool>(new MonoGramme_BoolConverter());
}
public static CsvWriter ConfigureWriter(CsvWriter writer)
{    
    writer.TypeConverterCache.AddConverter<bool>(new MonoGramme_BoolConverter());
}

/**  VS  **/
public static CsvWriter ConfigureWriter(IContextable csv)
{    
    csv.TypeConverterCache.AddConverter<bool>(new MonoGramme_BoolConverter());
}

Reading and writing CSV highly depend on the configuration, I can't trust dev to never fail a copy past. And forget to update copy pasted code, when specification gets more precises.

I cannot provide an all in one box, cause culture, encoding and medium (file,stream,http request, document). Is where the dev tinker to pipe the read read correctly.

Could we have a way to inject Configuration (now migrated in context) ?

UnnecessaryPunctuation avatar Jan 25 '22 12:01 UnnecessaryPunctuation

The context is per instance of CsvReader/CsvWriter and shouldn't be shared.

The configuration is essentially immutable as it's values are copied local in the constructor. Any mutable state got moved into the context.

I would suggest creating a method that creates an ICsvReader or ICsvWriter for you. You can encapsulate all the logic and configuration in one place then.

JoshClose avatar Jan 25 '22 19:01 JoshClose