Search code examples
c#csvhelper

CsvHelper, writing dynamic variable names (c#)


Assume want to write bank user account details in a following csv file format.

AccountId, Name, Jan, Feb, Mar ........... Dec
1, Anne, 1000.00, 400.00, 500.00 .......... 200.00
2, John, 900.00, 400.00, 500.00 .......... 1200.00
3, Brit, 600.00, 400.00, 500.00 .......... 2200.00

To represent this above data structure I have following model class:

class AccountBalance {
      int ID { get; set; };
      string Name { get; set; };
      List<string> lastTwelveMonths { get; set; };
}

My Code is to write csv is:

using (var stream = new MemoryStream())
using (var streamWriter = new StreamWriter(stream))
using (var stringWriter = new StringWriter())
using (var csvWriter = new CsvWriter(stringWriter))
{
    csvWriter.WriteRecords(listOfAccountBalances);
    streamWriter.Write(stringWriter.GetStringBuilder());
    streamWriter.Flush();
    stream.Position = 0;
    return stream.ToArray();
}

But above code will not give exact output when it comes to list of lastTwelveMonths. Could some one help?


Solution

  • You should be able to do this with a custom classmap:

    sealed class AccountBalanceMap : ClassMap<AccountBalance>
    {
        public AccountBalanceMap()
        {
            Map(x => x.ID);
            Map(x => x.Name);
            Map(x => x.lastTwelveMonths, false)
                .Name("Jan")
                .ConvertUsing(row => $"{row.lastTwelveMonths[0]}");
            Map(x => x.lastTwelveMonths, false)
                .Name("Feb")
                .ConvertUsing(row => $"{row.lastTwelveMonths[1]}");
            // ...
        }
    

    Register the class map with the CsvWriter before using it:

    csv.Configuration.RegisterClassMap<AccountBalanceMap>();
    

    You could even construct the class map dynamically using DateTimeFormatInfo.CurrentInfo.GetMonthName

    sealed class AccountBalanceMap : ClassMap<AccountBalance>
    {
        public AccountBalanceMap()
        {
            Map(x => x.ID);
            Map(x => x.Name);
            for (int i = 0; i < 12; i++)
            {
                var monthName = DateTimeFormatInfo.CurrentInfo.GetMonthName(i + 1);
                var monthIndex = i;
                Map(x => x.lastTwelveMonths, false)
                    .Name(monthName)
                    .ConvertUsing((row) => $"{row.lastTwelveMonths[monthIndex]}");
            }
        }
    }