2010-04-27 14 views
8

Todo lo que quiero es un diccionario que me diga qué clave no pudo encontrar, en lugar de simplemente decir The given key was not present in the dictionary."Diccionario verboso" en C#, 'anular nuevo' esto [] o implementar IDictionary

Consideré brevemente hacer una subclase con override new this[TKey key], pero sentí que era un poco hacky, así que me fui con la implementación de la interfaz IDictionary, y pasé todo directamente a un diccionario interior, con la única lógica adicional en el indexador:

public TValue this[TKey key] 
{ 
    get 
    { 
     ThrowIfKeyNotFound(key); 
     return _dic[key]; 
    } 
    set 
    { 
     ThrowIfKeyNotFound(key); 
     _dic[key] = value; 
    } 
} 
private void ThrowIfKeyNotFound(TKey key) 
{ 
    if(!_dic.ContainsKey(key)) 
     throw new ArgumentOutOfRangeException("Can't find key [" + key + "] in dictionary"); 
} 

¿Es esta la manera correcta/única de hacerlo? ¿Sería tan malo renovar este []?

Respuesta

10

suena como una buena opción para un método de extensión:

public static class SomeUtilClass { 
    public static TValue VerboseGetValue<TKey, TValue>(
     this IDictionary<TKey, TValue> data, TKey key) 
    { 
     TValue result; 
     if (!data.TryGetValue(key, out result)) { 
      throw new KeyNotFoundException(
       "Key not found: " + Convert.ToString(key)); 
     } 
     return result; 
    } 
} 

Esto luego trabajar en todos los diccionarios existentes cada vez que llame VerboseGetValue, por ejemplo:

var data = new Dictionary<int, string> { { 123, "abc" } }; 
    Console.WriteLine(data.VerboseGetValue(123)); 
    Console.WriteLine(data.VerboseGetValue(456)); 
+0

Estoy tan contento de que los usuarios # 1 y # 2 estén en el lado derecho del planeta :) – Benjol

1

Si desea hacer esto, tendrá que hacer las suyas de una forma u otra. Pero voy a preguntar ¿POR QUÉ querrías hacer esto?

+0

Bueno, pensé que dije por qué en la pregunta. Pero en lugar de recibir un mensaje del tipo que dice "¿qué valor me equivoqué?", ​​Prefiero que él mismo lo arregle. – Benjol

3

En vez de hacer ContainsKey y la comprobación de la presencia de la llave antes de tocar el diccionario subyacente, por qué no hacer

get { 
    try { 
     return _dic[key]; 
    } 
    catch (ArgumentOutOfRangeException) { 
     throw new ArgumentOutOfRangeException(......); 
    } 
} 

De esta manera, sólo se paga por la comprobación adicional en el caso de fallo - el caso de éxito , que afortunadamente es más común, no tiene que hacer una búsqueda adicional en el diccionario. Esto es bueno para get, pero set es más difícil ya que el comportamiento predeterminado del set es que siempre funcione. Si no quieres eso, primero deberías verificar la existencia de la clave.

+0

+1 Un controlador de excepción es la mejor manera de manejar una condición excepcional. Para eso están para. :) – HiredMind

+1

@Stewart A menos que me equivoque, 'System.Collections.Generic.Dictionary' no arroja un error en el indexador cuando no se encontró la clave, sino que se agrega silenciosamente con el nuevo valor. Sin embargo, su enfoque aún funcionaría para el comprador. –

+0

@ GeorgesDupéron - Tienes razón. Esto solo funciona en el caso get. Voy a modificar el ejemplo. Para el caso establecido, el control adicional es inevitable. – Stewart

Cuestiones relacionadas