Dicionário de design de dicionários em C #

5

Minha pergunta: existe uma maneira canônica de criar um dicionário de dicionários e fornecer um par de chaves externas / internas? Existe um NugetPackage com uma implementação?

No meu código, agora tenho alguns lugares onde tenho uma propriedade como esta

private readonly IDictionary<string, IDictionary<string, SomeType>> _nestedDict = 
        new Dictionary<string, IDictionary<string, SomeType>>();

e criei métodos de extensão como este

public static V AddOrUpdate<T, U, V>(
    [NotNull] this IDictionary<T, IDictionary<U, V>> dictionary,
    [NotNull] T outerKey,
    [NotNull] U innerKey,
    [NotNull] Func<V> addValueFactory,
    [NotNull] Func<V, V> updateValueFactory,
    [CanBeNull] IEqualityComparer<U> innerDictionaryComparer = null)
{
    IDictionary<U, V> dict;
    if (dictionary.TryGetValue(outerKey, out dict))
    {
        V currentValue;
        if (dict.TryGetValue(innerKey, out currentValue))
        {
            var updatedValue = updateValueFactory(currentValue);
            if (!object.ReferenceEquals(updatedValue, currentValue))
                dict[innerKey] = updatedValue;
            return updatedValue;
        }
        var addedValue1 = addValueFactory();
        dict[innerKey] = addedValue1;
        return addedValue1;
    }

    var addedValue = addValueFactory();
    if (innerDictionaryComparer != null)
        dictionary[outerKey] = new Dictionary<U, V>(innerDictionaryComparer) {{innerKey, addedValue}};
    else
        dictionary[outerKey] = new Dictionary<U, V> {{innerKey, addedValue}};
    return addedValue;
}

Isso é poderoso, mas estou começando a achar que eu deveria criar uma classe para dicionários aninhados. Aqui está o meu pensamento:

  1. Os addValueFactory e updateValueFactory são meio desajeitados e parece que está quebrando os princípios OO.
  2. Estou pensando em criar um ConcurrentDictionary de Dictionary s (ou talvez de ConcurrentDictionary s), e isso exigiria mais alguns métodos de extensão. Eu meio que pensei que se eu estivesse usando isso tanto que eu deveria criar a classe e acabar com isso.

O que você diz?

    
por Frank Bryce 23.05.2016 / 16:50
fonte

1 resposta

3

Pode haver um caminho mais simples para isso.

Considere isso:

    public class NAryDictionary<TKey, TValue> :
        Dictionary<TKey, TValue>
    {
    }

    public class NAryDictionary<TKey1, TKey2, TValue> :
        Dictionary<TKey1, NAryDictionary<TKey2, TValue>>
    {
    }

    public class NAryDictionary<TKey1, TKey2, TKey3, TValue> :
        Dictionary<TKey1, NAryDictionary<TKey2, TKey3, TValue>>
    {
    }

Então você pode escrever:

    class Program
    {
        static void Main(string[] args)
        {
            var dico3 = new NAryDictionary<bool, int, string, decimal>();

            dico3[false] = new NAryDictionary<int, string, decimal>();
            dico3[false][123] = new NAryDictionary<string, decimal>();
            dico3[false][123]["foo"] = 123456789.012m;

            Console.WriteLine(dico3[false][123]["foo"].ToString("0,0.000"));

            Console.ReadKey();
       }
    }

Agora, embora seja compatível com o Visual Studio intellisense (como você notará com as propostas automáticas de conclusão de código após digitar os sinais "=" nas atribuições acima), é indiscutivelmente um pouco incômodo, ainda, por causa disso

... new NAryDictionary<bool, int, string, decimal>()
... new NAryDictionary<int, string, decimal>()

e

... new NAryDictionary<string, decimal>()

Qual pode ser aliviado com

    public static class NAryDictionaryExtensions
    {
        public static NAryDictionary<TKey2, TValue> New<TKey1, TKey2, TValue>(this NAryDictionary<TKey1, TKey2, TValue> dictionary)
        {
            return new NAryDictionary<TKey2, TValue>();
        }

        public static NAryDictionary<TKey2, TKey3, TValue> New<TKey1, TKey2, TKey3, TValue>(this NAryDictionary<TKey1, TKey2, TKey3, TValue> dictionary)
        {
            return new NAryDictionary<TKey2, TKey3, TValue>();
        }
    }

permitindo agora escrever, de forma mais simples,

    class Program
    {
        static void Main(string[] args)
        {
            var dico3 = new NAryDictionary<bool, int, string, decimal>();

            dico3[true] = dico3.New();
            dico3[true][456] = dico3[true].New();
            dico3[true][456]["bar"] = 456789012.345m;

            Console.WriteLine(dico3[true][456]["bar"].ToString("0,0.000"));

            Console.ReadKey();
       }
    }

'Espero que isso ajude.

    
por 07.10.2016 / 22:09
fonte