Search code examples
c#csvhelperexpandoobject

Getting values of ExpandoObject from Keys that are known at runtime


I am using CsvHelper to read a CSV file so I can write "some" of its columns to somewhere else. I don't have the name of headers beforehand so I couldn't use ClassMapper . However I can get a List of the names of columns at runtime because they are provided in a separate file so if I can read that file I can fill up a List<string> with name of the headers of the CSV that I am reading.

My question is now how can I use Key names of the ExpandoObject so I can get the value from them? Remember at runtime I do have a List<string> that holds the keys/header names.

The two commented-out lines below are what I tried but failed.

List<string> list = new List<string>();
list.Add("LastName");
using(var streamReader = new StreamReader(@"C:\csvtesting\myfile.csv"))
{
    using(var csvReader = new CsvReader(streamReader, CultureInfo.InvariantCulture))
    {
        var records = csvReader.GetRecords<dynamic>().ToList();
        var one = records.First();
        //one.Where(v => v.Key == list[0]).Select(x => x.Value).FirstOrDefault(); // cannot cast error
        //var ddd = one.list[0]; // crash
        var iWish = one.LastName; // but how to do this dynamically?
    }
}

Solution

  • One option is to use the fact that underlying type of dynamic in this case would be ExpandoObject which implements IDictionary<string, object>:

    var one = records.First() as IDictionary<string, object>;
    var iWish = one[list[0]]; // or TryGetValue, also can check the headers
    

    Note that you can process the csv "dynamically" without using dynamic (which, I would argue, in general case should be avoided) but using while loop and GetField API (see the Reading by Hand doc):

    using (var csv = new CsvReader(streamReader, CultureInfo.InvariantCulture))
    {
        csv.Read();
        csv.ReadHeader();
        while (csv.Read())
        {
            string? iWish = csv.GetField(list[0]);
            string? iWishByIndex = csv.GetField(0); // if it is first column
            break; // just for sake of the example
        }
    }