Search code examples
c#csvhelper

CsvHelper define custom mapping for a column


I am trying to have a column not provided in the CSV file populated using CSVHelper. This is an example of the CSV I need to import

Id
10
123
45
213

The class I am trying to deserialize to is this one:

public class Foo {
    public int Id { get; set }
    public string Name { get; set }
}

With the default configuration I get this error:

CsvHelper.HeaderValidationException: 'Header with name 'Name' was not found.

I would like to have the possibility to define a mapper so that the column Name could be populated by the parser (e.g. by providing a dictionary of values). Any way to do this?

Thanks

---------- EDIT

Just to clarify, the idea is to have something like a converter that, associated to a field, would be used to decode the Id to the Name

public class NameConverter
{
    public NameConverter()
    {
        employeesList = new Dictionary<int, string>()
        {
            { 10, "Mary" },
            { 45, "Mike" },
            { 123, "Jack" },
            { 213, "Suzanne" },
        };
    }

    IDictionary<int, string> employeesList;

    public string GetValue(int id) => employeesList[id];
}

The alternative, I would imagine, is to ignore the Name field as suggested and inject the NameConverter in the Foo class and make the Name a get only property.


Solution

  • void Main()
    {
        var s = new StringBuilder();
        s.AppendLine("Id");
        s.AppendLine("45");
        s.AppendLine("123");
        using (var reader = new StringReader(s.ToString()))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            csv.Configuration.RegisterClassMap<FooMap>();
            csv.GetRecords<Foo>().ToList().Dump();
        }
    }
    
    public class Foo
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    public class FooMap : ClassMap<Foo>
    {
        public FooMap()
        {
            var nameConverter = new NameConverter();
            Map(m => m.Id);
            Map(m => m.Name).ConvertUsing(row => nameConverter.GetValue(row.GetField<int>(nameof(Foo.Id))));
        }
    }
    
    public class NameConverter
    {
        public NameConverter()
        {
            employeesList = new Dictionary<int, string>()
            {
                { 10, "Mary" },
                { 45, "Mike" },
                { 123, "Jack" },
                { 213, "Suzanne" },
            };
        }
    
        IDictionary<int, string> employeesList;
    
        public string GetValue(int id) => employeesList[id];
    }
    

    Output:

    enter image description here