una ronald romualfons romualdfons romu que posicionar posicionamiento home google description curso como c# dictionary extension-methods keynotfoundexception

c# - ronald - ¿Qué mecanismo es una mejor manera de extender el Diccionario para tratar con las claves que faltan y por qué?



ronald seo (3)

Al nombrar un método de extensión destinado a reemplazar un método existente, tiendo a agregar al nombre del método por especificidad en lugar de acortarlo:

GetValueOrDefault(...)

En cuanto a ForgivingDictionary , puede restringir TKey para que no sea un tipo de valor. Sin embargo, si debe tratar con los tipos de valor en él, devolverá algo para un tipo de valor y la mejor opción es devolver el default(TKey) ya que no puede devolver el null .

Sinceramente, me gustaría ir con el método de extensión.

Edición : GetValueOrDefault() , por supuesto, no se agregaría al diccionario si no encontrara la clave. Solo devolvería un valor predeterminado si no se encontrara, porque así es como se llama. Si uno quisiera que también se insertara, un buen nombre sería GetValueOrInsertDefault() .

Hay una pequeña molestia con la que me encuentro mucho: tengo un Dictionary<TKey, TValue> que contiene valores que pueden o no estar allí.

Así que el comportamiento normal sería usar el indexador, como este:

object result = myDictionary["key"];

Sin embargo, si la "key" no está en el diccionario, esto arroja una KeyNotFoundException , por lo que debe hacer esto en su lugar:

object val; if (!myDictionary.TryGetValue("key", out val)) { val = ifNotFound; }

Lo cual está bien, excepto que puedo tener una carga de estos en una fila: TryGetValue comienza a sentirse terriblemente torpe.

Así que la opción 1 es un método de extensión:

public static TValue TryGet<TKey, TValue>( this Dictionary<TKey, TValue> input, TKey key, TValue ifNotFound = default(TValue)) { TValue val; if (input.TryGetValue(key, out val)) { return val; } return ifNotFound; }

Lo que me permite hacer:

object result = myDictionary.TryGet("key1") ?? ifNotFound; int i = anotherDictionary.TryGet("key2", -1);

Lo que es bastante simple, pero un método de extensión adicional con un nombre similar a los métodos de instancia existentes potencialmente agrega confusión y reduce la capacidad de mantenimiento. Tampoco es compatible con el conjunto de indexador del diccionario, que manejará las claves que faltan.

Así que la opción 2 es una nueva implementación de IDictionary<TKey, TValue> con un lanzamiento implícito del Dictionary<TKey, TValue> pero un indexador que devuelve el default(TValue) lugar de lanzar una KeyNotFoundException .

Eso me deja hacer:

ForgivingDictionary<string, object> dict = myDictionary; object val = dict["key"] ?? ifNotFound; // do stuff to val, then... dict["key"] = val;

Así que ahora los valores de obtener y establecer son consistentes, pero los tipos de valor son más desordenados y ForgivingDictionary implica mucho más código.

Ambos métodos parecen "desordenados": ¿existe una mejor manera de hacerlo ya en .Net?

Ambos métodos hacen compromisos que podrían causar confusión, pero ¿es uno más obvio / claro que el otro? ¿Y por qué?


No puedo deducir de su pregunta qué se debe hacer cuando no se encuentra una clave. Puedo imaginar que no se debe hacer nada en ese caso, pero también puedo imaginar lo contrario. De todos modos, una alternativa elegante para una serie de estas declaraciones TryGetValue que describe, es usar uno de los siguientes métodos de extensión. He proporcionado dos opciones, según si se debe hacer algo o no cuando el diccionario no contiene la clave:

/// <summary> Iterates over all values corresponding to the specified keys, ///for which the key is found in the dictionary. </summary> public static IEnumerable<TValue> TryGetValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keys) { TValue value; foreach (TKey key in keys) if (dictionary.TryGetValue(key, out value)) yield return value; } /// <summary> Iterates over all values corresponding to the specified keys, ///for which the key is found in the dictionary. A function can be specified to handle not finding a key. </summary> public static IEnumerable<TValue> TryGetValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keys, Action<TKey> notFoundHandler) { TValue value; foreach (TKey key in keys) if (dictionary.TryGetValue(key, out value)) yield return value; else notFoundHandler(key); }

Código de ejemplo sobre cómo usar esto es:

TKey[] keys = new TKey{...}; foreach(TValue value in dictionary.TryGetValues(keys)) { //some action on all values here }


O quizás

public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> input, TKey key) { return input.ContainsKey(key) ? input[key] : *some default value*; }