Search code examples
c#csvcsvhelper

Using CSVHelper to serialise and deserialise a Dictionary<TKey,Value>?


Is it possible to read and write a CSV file using CSVHelpers from a dictionary?

Here is a snippet of my write code :

using var writer = new StreamWriter(_filePath);
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
if (_classMap != null)
{
    csv.Context.RegisterClassMap(_classMap);
}
csv.WriteHeader(typeof(Dictionary<TKey, TValue>));
csv.NextRecord();

foreach (var value in _store)
{
     csv.WriteRecord(new KeyValuePair<TKey,TValue>(value.Key,value.Value));
     csv.NextRecord();
}

Here is a snipped of my read code:

using var reader = new StreamReader(_filePath);
using var csv = new CsvReader(reader, CultureInfo.InvariantCulture);
_ = csv.Read();
_ = csv.ReadHeader();

if (_classMap != null)
{
    csv.Context.RegisterClassMap(_classMap);
}

while (csv.Read())
{
    var key = csv.GetField<TKey>(0);
    var value = csv.GetRecord<TValue>();

    _store[key] = value;
}

The shape of the Dictionary is of type <int,Sequence> where the Sequence object looks like:

public class Sequence
{
    public int SequenceId { get; set; }
    public int NextId { get; set; }
}

I've tried a few different ways to do it, but I get the following exception each time:

System.MissingMethodException: Constructor 'CsvHelper.Configuration.DefaultClassMap`1[[System.Collections.Generic.KeyValuePair`2[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e0
9],[FourDBS.SmartMeter.Common.Managers.Sequence, Four.DBS.Meadow.SmartMeter.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]()'

Solution

  • You are close. You just need to write out the dictionary id and then write the Sequence value. The same with reading. Use GetField<int>("DictionaryId") and GetRecord<Sequence>(). You can use a ClassMap<Sequence> if you want to alter how Sequence is written.

    void Main()
    {
        var _filePath = @"C:\Temp\SerializeDictionary.csv";
        ClassMap<Sequence> _classMap = null;
    
        var data = new Dictionary<int, Sequence>(){
            { 1, new Sequence { SequenceId = 1, NextId = 2} },
            { 2, new Sequence { SequenceId = 2, NextId = 3} },
        };
    
        using (var writer = new StreamWriter(_filePath))
        using (var csv = new CsvWriter(writer, CultureInfo.InvariantCulture))
        {
            if (_classMap != null)
            {
                csv.Context.RegisterClassMap(_classMap);
            }
            csv.WriteField("DictionaryId");
            csv.WriteHeader<Sequence>();
            csv.NextRecord();
    
            foreach (var value in data)
            {
                csv.WriteRecord(value.Key);
                csv.WriteRecord(value.Value);
                csv.NextRecord();
            }
        }
    
    
        var _store = new Dictionary<int, Sequence>();
        using (var reader = new StreamReader(_filePath))
        using (var csv = new CsvReader(reader, CultureInfo.InvariantCulture))
        {
            _ = csv.Read();
            _ = csv.ReadHeader();
    
            if (_classMap != null)
            {
                csv.Context.RegisterClassMap(_classMap);
            }
    
            while (csv.Read())
            {
                var key = csv.GetField<int>("DictionaryId");
                var value = csv.GetRecord<Sequence>();
    
                _store[key] = value;
            }
        }
    }
    
    // You can define other methods, fields, classes and namespaces here
    public class Sequence
    {
        public int SequenceId { get; set; }
        public int NextId { get; set; }
    }