kofifus
kofifus

Reputation: 19276

C# Nested ConcurrentDictionary wrapper

There seem to be no way to nest ConcurrentDictionary so that they share one lock

I am trying to create a class that will wrap a 3-deep nested dictionary with a lock

So that I can do NestedDict[k1][k2][k3] and get a value in a concurrent safe way And do NestedDict[k1][k2] and get a ConcurrentDictionary or equivalent.

I am not looking for a solution inheriting or composing ConcurrentDictionary<Tuple<TK1,TK2,TK3>,V> as it is not the same, it will not allow me to ie efficiently get all keys of dict[k1, k2]

How can this be implemented ?

Is there an existing generic library/code showing such nested dictionary implementation (including iterators etc) ?

Upvotes: 0

Views: 718

Answers (1)

Adam G
Adam G

Reputation: 1323

Here is one approach that you can take

using System;
using System.Collections.Concurrent;

public class Program
{
    public class NestedDictionary<TK1, TK2, TK3, TValue>
    {
        private readonly ConcurrentDictionary<Tuple<TK1, TK2, TK3>, TValue> storage = new ConcurrentDictionary<Tuple<TK1, TK2, TK3>, TValue>();
        public TValue this[TK1 key1, TK2 key2, TK3 key3]
        {
            get => this.storage[new Tuple<TK1, TK2, TK3>(key1, key2, key3)];
            set => this.storage[new Tuple<TK1, TK2, TK3>(key1, key2, key3)] = value;
        }

        public bool TryGetValue(TK1 key1, TK2 key2, TK3 key3, out TValue value)
        {
            return this.storage.TryGetValue(new Tuple<TK1, TK2, TK3>(key1, key2, key3), out value);
        }

        public bool TryAdd(TK1 key1, TK2 key2, TK3 key3, TValue value)
        {
            return this.storage.TryAdd(new Tuple<TK1, TK2, TK3>(key1, key2, key3), value);
        }

        // etc etc

    }

    public static void Main()
    {
        NestedDictionary<int, bool, DateTime, string> d = new NestedDictionary<int, bool, DateTime, string>();
        d[1, false, new DateTime(2018, 6, 18)] = "Hello";
        d[1, true, new DateTime(2018, 6, 18)] = "World";
        d[2, false, new DateTime(2018, 6, 18)] = "Foo";
        d[2, false, new DateTime(2018, 6, 19)] = "Bar";
        Console.WriteLine(d[1, true, new DateTime(2018, 6, 18)]); // World
    }
}

You could even at a pinch implement the IDictionary methods. Given that Tuple internally gives you a good spread on your hashcodes from the composite keys, it should have very similar performance characteristics of three separate dictionaries in a nest.

Upvotes: 2

Related Questions