2012-02-16 15 views
16

Mam struktury, które można bardzo łatwo przedstawić za pomocą trzech głęboko zagnieżdżone słownika, tak jakCzy głęboko zagnieżdżony słownik jest antypodstawą?

private static Dictionary<string, Dictionary<string, Dictionary<string,string>>> PrerenderedTemplates; 

przypadku gdy struktura może być używany coś jak ten

PrerenderedTemplates[instanceID][templategroup][templatepart] 

Teraz zdaję sobie sprawę, że Kod ten jest trudny do odczytania, ponieważ patrząc na definicję, nie można stwierdzić, do czego służy. Jedyną zaletą, którą naprawdę widzę w zmianie na Dictionary<string, PrerenderedTemplate> jest czytelność. Konwersja każdego zagnieżdżenia do własnej klasy (np. class PrerenderedTemplate{} class TemplateGroup{} class TemplatePart{}) dodawałaby o wiele więcej linii kodu przy niewielkiej (jeśli jakąkolwiek) przewadze obliczeniowej. O ile widzę.

  • Tak, czy moje podejście jest "ok", czy powinienem zrobić więcej i stworzyć oddzielne klasy?
  • Czy można w prosty sposób opisać, w jaki sposób zagnieżdżona Dictionary działa w dokumentacji/komentarzach
  • Czy istnieje najlepsza praktyka do obsługi tego rodzaju zagnieżdżania?
  • Pamiętaj, że jest to prywatny użytkownik, nie musi być prosty dla osób korzystających z klasy.

Aktualizacja

Więc, zainspirowany Rezy, ale nie można używać krotek, postanowiłem stworzyć własny generator klucza i wykonywać swój wzór takiego:

private Dictionary<string, string> PrerenderedTemplates; 
private string GetPrerenderedTemplateKey(string InstanceId, string FeatureId, string OptionId) 
{ 
    return new StringBuilder(instanceId) 
    .Append(FormatTools.LIST_ENTRY_DELIMITER) 
    .Append(templategroup) 
    .Append(FormatTools.LIST_ENTRY_DELIMITER) 
    .Append(templatepart).ToString(); 
} 

Gdzie FormatTools.LIST_ENTRY_DELIMITER jest znak prywatnego użytku Unicode 0xe04d.

+0

Ponieważ dwa pierwsze zagnieżdżenia są w zasadzie tylko identyfikatorami, być może uda mi się uciec prostym słownikiem . Więc 'PrerenderedTemplates [" instance1 "] [" fruit "] [" banana "]' może być po prostu reprezentowane jako 'PrerenderedTemplates [" instance1_fruit_banana "]', podobnie jak przestrzeń nazw. –

+0

Czy potrzebujesz możliwości używania 'PrerenderedTemplates' do wyświetlania grup szablonów lub części szablonów? Sortowanie w sposób 'PrerenderedTemplates [instanceID] .Keys' lub' PrerenderedTemplates [instanceID] [templateGroup] '? Jeśli tak, to prawdopodobnie jest to najprostszy sposób, aby sobie z tym poradzić. –

+0

@ M.Babcock, no cóż, zapętlałem kolekcję obiektów zawierających metadane wskazujące, jak renderować szablon. Przed renderowaniem tego szablonu chcę sprawdzić mój słownik, aby upewnić się, że nie został wcześniej wyrenderowany. Jeśli nie, renderuję go i dodaję wynik do mojego słownika. (Zarządzanie zmianą szablonów jest obsługiwane w innym miejscu) –

Odpowiedz

14

Oferuję innego wyboru:

Dictionary<Tuple<string, string, string>, string> pt; 

Dostęp do słownika:

pt[Tuple.Create("id","group","part")] 
+0

Fajnie, na pewno dam to i powiedz, jak to działa! –

+0

Nie rozumiem twojego podłego !! –

+2

Przepraszam, Reza, mówiłem ci, że podoba mi się twoje podejście i zamierzam to wypróbować. Powinienem starać się nie używać tak dużo slangu. –

1

Chciałbym utworzyć słownik niestandardowy. Coś takiego

public class TrippleKeyDict 
{ 
    private const string Separator = "<|>"; 
    private Dictionary<string, string> _dict = new Dictionary<string, string>(); 

    public string this[string key1, string key2, string key3] 
    { 
     get { return _dict[GetKey(key1, key2, key3)]; } 
     set { _dict[GetKey(key1, key2, key3)] = value; } 
    } 

    public void Add(string key1, string key2, string key3, string value) 
    { 
     _dict.Add(GetKey(key1, key2, key3), value); 
    } 

    public bool TryGetValue(string key1, string key2, string key3, out string result) 
    { 
     return _dict.TryGetValue(GetKey(key1, key2, key3), out result); 
    } 

    private static string GetKey(string key1, string key2, string key3) 
    { 
     return String.Concat(key1, Separator, key2, Separator, key3); 
    } 
} 

Jeśli uważasz, łącząc strun nie jest wystarczająco bezpieczny, ponieważ klucze mogą zawierać separatorów, a następnie użyć własnego rodzaj klucza lub Touple<string,string,string> jako klucza. Ponieważ ten szczegół implementacji jest ukryty w Twoim słowniku niestandardowym, możesz go zmienić w dowolnym momencie.

Można użyć słownika jak ten

var dict = new TrippleKeyDict(); 

// Using the Add method 
dict.Add(instanceID, templategroup, templatepart, "some value"); 

// Using the indexer 
dict[instanceID, templategroup, templatepart] = "xy"; 
string result = dict[instanceID, templategroup, templatepart]; 

// Using the TryGetValue method 
if (dict.TryGetValue(instanceID, templategroup, templatepart, out result)) { 
    // Do something with result 
} 
+1

Widzę, co masz na myśli. Zderzenie wystąpi z 'hello_world> hooray> stuff' i' hello> world_hooray> stuff'. Oba będą używać klucza "hello_world_hooray_stuff" ... –

+0

Użyłem "" | "' jako separatora. Możesz użyć innego, z którego wiesz, że nigdy nie jest używane w twoich kluczach, jak '' <|> "'. –

+0

Ramy, na których to buduję, używają bardzo niejasnego znaku Unicode jako ogranicznika. Odważ się, że tego użyję! :) –

0

Chciałbym zaoferować alternatywne podejście, stosując SortedDictionary i niestandardową porównywarka:

public class PrerenderedTemplate 
    { 
     public string instanceID; 
     public string templategroup; 
     public string templatepart; 

     public PrerenderedTemplate(string id, string tempGroup, string tempPart) 
     { 
      instanceID = id; 
      templategroup = tempGroup; 
      templatepart = tempPart; 
     } 

     // custom comparer instance used as argument 
     // to SortedDictionary constructor 
     public class Comparer : IComparer<PrerenderedTemplate> 
     { 
      public int Compare(PrerenderedTemplate x, PrerenderedTemplate y) 
      { 
       int compare = 0; 
       if (compare == 0) compare = x.instanceID.CompareTo(y.instanceID); 
       if (compare == 0) compare = x.templategroup.CompareTo(y.templategroup); 
       if (compare == 0) compare = x.templatepart.CompareTo(y.templatepart); 
       return compare; 
      } 
     } 
    } 

Służy tak:

var dictionary = new SortedDictionary<PrerenderedTemplate, string>(new PrerenderedTemplate.Comparer()); 

    dictionary.Add(new PrerenderedTemplate("1", "2", "3"), "123"); 
    dictionary.Add(new PrerenderedTemplate("4", "5", "6"), "456"); 
    dictionary.Add(new PrerenderedTemplate("7", "8", "9"), "789"); 

    Assert.AreEqual<string>(dictionary[new PrerenderedTemplate("7", "8", "9")], "789"); 

Reza Odpowiedź araba jest odpowiednia do celu, ale osobiście nie lubię krotek na podstawie ich niejednoznacznych właściwości i pełnej składni.

Klasa niestandardowa z porównywarką zapewnia większą przejrzystość i elastyczność w przypadku zmiany wymagań.

Powiązane problemy