Question

Is it possible to serialize the following class using protobuf-net? I have looked all over and I cannot find any examples for such a scenario?

  [ProtoContract]
  public class Example
  {
    [ProtoMember(1)]
    public ConcurrentDictionary<int, string> CategoryNames;
    [ProtoMember(2)]
    public ConcurrentDictionary<int, int[]> TaxonomyMap;
    [ProtoMember(3)]
    public ConcurrentDictionary<int, Dictionary<int, int>>[] Tokens;  
  }

I currently get the standard "Nested or jagged lists and arrays are not supported". However, I am not sure how to map such a class?

EDIT: Based on @Marc's suggestion below, I was able to successfully use protobuf-net to serialize the class above. For completeness, I have added my solution below:

The following class was created which contains a list of ModelPartition objects:

[ProtoContract]
public class GenomeModel
{
    [ProtoMember(1)]
    public ConcurrentDictionary<int, string> categoryNames = 
        new ConcurrentDictionary<int, string>();
    [ProtoMember(2)]
    public ConcurrentDictionary<int, int[]> taxonomyMap = 
        new ConcurrentDictionary<int, int[]>();
    [ProtoMember(3)]
    public List<ModelPartition> geneTokens = new List<ModelPartition>();
}

The ModelPartition object is used to "abstract away" the array of ConcurrentDictionary by saving each index position and individual ConcurrentDictionary member in a separate ModelPartition object which is then placed in the GenomeModel.geneTokens ModelPartition list:

[ProtoContract]
public class ModelPartition
{
    [ProtoMember(1)]
    public int partitionNo;
    [ProtoMember(2)]
    public ConcurrentDictionary<int, Dictionary<int, int>> partitionData;

    public ModelPartition(int PartitionNo
               , ConcurrentDictionary<int, Dictionary<int, int>> PartitionData)
    { 
        partitionNo = PartitionNo;
        partitionData = PartitionData;
    }
}

Finally during serialization, a short conversion is used to load data from the original "Example" object into the GenomeModel object using the ModelPartition's as a wrapper object:

GenomeModel genomeModel = new GenomeModel();
genomeModel.categoryNames = strand.categoryNames;
genomeModel.taxonomyMap = strand.taxonomyMap;

for (int i = 0; i < strand.minhashSignatureSize; i++)
{
    genomeModel.geneTokens.Add(new ModelPartition(i, strand.geneTokens[i]));
}

using (var file = File.Create(commandAgrs[0]))
{
    Serializer.Serialize<GenomeModel>(file, genomeModel);
}

Thanks Marc!

Was it helpful?

Solution

ConcurrentDictionary<TKey,TValue> works fine. The problem is the ConcurrentDictionary<TKey,TValue>[] - which is essentially (from the library's perspective) the same layout as KeyValuePair<TKey, TValue>[][] - i.e. a nested array. If you need that, consider having an array (or list) of things that each have a dictionary, rather than an array of dictionaries.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top