Search code examples
c#csvhelper

Csvhelper set index dynamically to different csv


I receive different CSV without header (we agreed about the content but not the format) from different customers, and I'm trying to build a generic class that can parse it hard coupling it with CSVHelper (who knows if tomorrow it is not supported anymore). For example the first customer send a CSV as "Name;Lastname;Age;Birthplace", the second customer send it as "Birthplace;Lastname;Firstname;Age", and another customer sends "Firstname;Lastname". I create a custom attribute in which I put the index expected, and at runtime I would like to add the IndexAttribute from CsvHelper.

partial class CustomAttribute : Attribute
{
    public int Index { get; set; }
}

public class PersonCustomer1 : IPerson
{
    [CustomAttribute(Index = 0)]
    public string Name { get; set; }

    [CustomAttribute(Index = 1)]
    public string Lastname { get; set; }

    [CustomAttribute(Index = 3)]
    public int Age { get; set; }
}

public class PersonCustomer2 : IPerson
{
    [CustomAttribute(Index = 2)]
    public string Name { get; set; }

    [CustomAttribute(Index = 1)]
    public string Lastname { get; set; }

    [CustomAttribute(Index = 0)]
    public int Age { get; set; }

    [CustomAttribute(Index = 3)]
    public int Gender { get; set; }
}

The generic converter is build as

public class ConverterCsv<T>
{

    public IEnumerable<T> Convert(FileInfo fileInfo)
    {
        IEnumerable<T> records = new List<T>();
        using (var reader = fileInfo.OpenText())
        using (var csv = new CsvReader(reader))
        {
            csv.Configuration.HasHeaderRecord = false;
            csv.Configuration.RegisterClassMap<CsvGenericMap<T>>();
            records = csv.GetRecords<T>().ToList();
        }

        return records;
    }
}

public sealed class CsvGenericMap<T> : ClassMap<T>
{
    public CsvGenericMap()
    {
        foreach (var property in typeof(T).GetProperties())
        {
            var attribute = property?.GetCustomAttribute<CustomAttribute>();
          //what now? How should I inject the CsvHelper.Configuration.Attributes.Index attribute?
        }
    }
}

I would expect that any csv, with its custom attribute set, will fill the class.


Solution

  • public sealed class CsvGenericMap<T> : ClassMap<T>
    {
        public CsvGenericMap()
        {
            foreach (var property in typeof(T).GetProperties())
            {
                var attribute = property?.GetCustomAttribute<CustomAttribute>();
    
                Map(typeof(T), property).Index(attribute.Index);
            }
        }
    }