2012-02-16 22 views
16

que tienen una estructura que se puede representar muy fácilmente usando un diccionario anidada de tres de profundidad, al igual que¿Es un diccionario anidado profundo un antipatrón?

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

Cuando la estructura se podría utilizar algo como esto

PrerenderedTemplates[instanceID][templategroup][templatepart] 

Ahora, darse cuenta de que este código es difícil de leer porque, al mirar la declaración de definición, no se puede decir para qué se está utilizando. La única ventaja que realmente puedo ver al cambiarlo a Dictionary<string, PrerenderedTemplate> es la legibilidad. La conversión de cada anidación en su propia clase (por ejemplo, class PrerenderedTemplate{} class TemplateGroup{} class TemplatePart{}) agregaría muchas más líneas de código para una pequeña ventaja computacional (si la hubiera). Por lo que puedo ver.

  • Entonces, ¿mi enfoque es "correcto" o debería hacer un esfuerzo adicional y crear clases separadas?
  • ¿Está bien que cubra cómo funciona el Dictionary anidado en la documentación/comentarios
  • ¿Existe una mejor práctica para manejar este tipo de anidación?
  • Tenga en cuenta que este es un miembro privado, no es necesario que sea sencillo para las personas que usan la clase.

actualización

Así, inspirado por Reza, pero no puede utilizar tuplas, decidí crear mi propio generador de clave y poner en práctica su patrón de esta manera:

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(); 
} 

Dónde FormatTools.LIST_ENTRY_DELIMITER es el carácter de uso privado Unicode 0xe04d.

+0

Dado que las dos primeras agrupaciones son esencialmente solo identificadores, quizás podría salirse con la suya con un simple diccionario . Entonces 'PrerenderedTemplates [" instance1 "] [" fruit "] [" banana "]' podría representarse como 'PrerenderedTemplates [" instance1_fruit_banana "]', como un espacio de nombres. –

+0

¿Necesita la capacidad de utilizar 'PrerenderedTemplates' para listar sus grupos de plantillas o partes de plantilla? Más o menos en el estilo de 'PrerenderedTemplates [instanceID]. Keys' o' PrerenderedTemplates [instanceID] [templateGroup] '? Si es así, esta es probablemente la forma más fácil de manejarlo. –

+0

@ M.Babcock, bueno, estoy recorriendo una colección de objetos que contienen metadatos que apuntan a cómo renderizar una plantilla. Antes de representar esa plantilla, quiero verificar mi diccionario para asegurarme de que no se haya procesado antes. Si no lo ha hecho, lo renderizo y agrego el resultado a mi Diccionario. (La gestión del cambio de plantilla se maneja en otro lado) –

Respuesta

14

me ofrecen otra opción:

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

acceso a diccionario:

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

Bien, definitivamente voy a probar esto y le contaré cómo funciona. –

+0

¡¡No entiendo tu significado !! –

+2

Lo siento Reza, te dije que me gusta tu enfoque y voy a intentarlo. Debería tratar de no usar tanto jerga. –

1

me gustaría crear un diccionario personalizado. Algo como esto

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); 
    } 
} 

Si usted piensa, la concatenación de las cadenas no es lo suficientemente seguro, porque las llaves podrían contener los separadores, a continuación, utilizar su propio tipo de clave o una Touple<string,string,string> como clave. Dado que este detalle de implementación está oculto dentro de su diccionario personalizado, puede cambiarlo en cualquier momento.

Puede usar el diccionario como este

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

Veo lo que quieres decir. Un choque ocurriría con 'hello_world> hurra> cosas' y' hello> world_hooray> cosas'. Ambos utilizarían la clave "hello_world_hooray_stuff" ... –

+0

Utilicé '" | "' como separador. Puede usar otra de la que sepa que nunca se usa en sus claves, como '" <|> ''. –

+0

El marco en el que estoy desarrollando esto utiliza un carácter unicode muy oscuro como delimitador. ¡Atrévete a decir que usaré eso! :) –

0

me gustaría ofrecer un enfoque alternativo, utilizando un SortedDictionary y un comparador personalizado:

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; 
      } 
     } 
    } 

¿Se utiliza este modo:

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 La respuesta de Arab es adecuada para mi propósito, pero personalmente no me gusta Tuples sobre la base de sus propiedades ambiguas y su sintaxis detallada.

Una clase personalizada con comparer ofrece más claridad y flexibilidad, en caso de que los requisitos cambien.

Cuestiones relacionadas