values initialize c# collections dictionary

c# - initialize - Diccionario que devuelve un valor predeterminado si la clave no existe



initialize dictionary c# (4)

¡ DefaultableDictionary un DefaultableDictionary para hacer exactamente lo que estás pidiendo!

using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; namespace DefaultableDictionary { public class DefaultableDictionary<TKey, TValue> : IDictionary<TKey, TValue> { private readonly IDictionary<TKey, TValue> dictionary; private readonly TValue defaultValue; public DefaultableDictionary(IDictionary<TKey, TValue> dictionary, TValue defaultValue) { this.dictionary = dictionary; this.defaultValue = defaultValue; } public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() { return dictionary.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Add(KeyValuePair<TKey, TValue> item) { dictionary.Add(item); } public void Clear() { dictionary.Clear(); } public bool Contains(KeyValuePair<TKey, TValue> item) { return dictionary.Contains(item); } public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { dictionary.CopyTo(array, arrayIndex); } public bool Remove(KeyValuePair<TKey, TValue> item) { return dictionary.Remove(item); } public int Count { get { return dictionary.Count; } } public bool IsReadOnly { get { return dictionary.IsReadOnly; } } public bool ContainsKey(TKey key) { return dictionary.ContainsKey(key); } public void Add(TKey key, TValue value) { dictionary.Add(key, value); } public bool Remove(TKey key) { return dictionary.Remove(key); } public bool TryGetValue(TKey key, out TValue value) { if (!dictionary.TryGetValue(key, out value)) { value = defaultValue; } return true; } public TValue this[TKey key] { get { try { return dictionary[key]; } catch (KeyNotFoundException) { return defaultValue; } } set { dictionary[key] = value; } } public ICollection<TKey> Keys { get { return dictionary.Keys; } } public ICollection<TValue> Values { get { var values = new List<TValue>(dictionary.Values) { defaultValue }; return values; } } } public static class DefaultableDictionaryExtensions { public static IDictionary<TKey, TValue> WithDefaultValue<TValue, TKey>(this IDictionary<TKey, TValue> dictionary, TValue defaultValue ) { return new DefaultableDictionary<TKey, TValue>(dictionary, defaultValue); } } }

Este proyecto es un simple decorador para un objeto IDictionary y un método de extensión para que sea fácil de usar.

DefaultableDictionary permitirá crear un contenedor alrededor de un diccionario que proporciona un valor predeterminado al intentar acceder a una clave que no existe o enumerar a través de todos los valores en un IDictionary.

Ejemplo: var dictionary = new Dictionary<string, int>().WithDefaultValue(5);

Publicación del blog sobre el uso también.

Me encuentro utilizando el patrón actual con bastante frecuencia en mi código hoy en día

var dictionary = new Dictionary<type, IList<othertype>>(); // Add stuff to dictionary var somethingElse = dictionary.ContainsKey(key) ? dictionary[key] : new List<othertype>(); // Do work with the somethingelse variable

O algunas veces

var dictionary = new Dictionary<type, IList<othertype>>(); // Add stuff to dictionary IList<othertype> somethingElse; if(!dictionary.TryGetValue(key, out somethingElse) { somethingElse = new List<othertype>(); }

Ambas formas se sienten bastante indirectas. Lo que realmente me gustaría es algo como

dictionary.GetValueOrDefault(key)

Ahora, podría escribir un método de extensión para la clase de diccionario que hace esto por mí, pero pensé que podría estar perdiendo algo que ya existe. Entonces, ¿hay alguna forma de hacer esto de una manera que sea más "fácil de entender" sin escribir un método de extensión en el diccionario?


No, nada de eso existe. El método de extensión es el camino a seguir, y su nombre ( GetValueOrDefault ) es una muy buena opción.


Sé que esta es una publicación anterior y sí estoy a favor de los métodos de extensión, pero esta es una clase simple que uso de vez en cuando para manejar diccionarios cuando necesito valores predeterminados.

Desearía que esto fuera parte de la clase básica del diccionario.

public class DictionaryWithDefault<TKey, TValue> : Dictionary<TKey, TValue> { TValue _default; public TValue DefaultValue { get { return _default; } set { _default = value; } } public DictionaryWithDefault() : base() { } public DictionaryWithDefault(TValue defaultValue) : base() { _default = defaultValue; } public new TValue this[TKey key] { get { TValue t; return base.TryGetValue(key, out t) ? t : _default; } set { base[key] = value; } } }

Ten cuidado, sin embargo. Al subclasar y usar new (ya que override no está disponible en el tipo de Dictionary nativo), si un objeto DictionaryWithDefault se reubica en un Dictionary simple, llamar al indexador utilizará la implementación del Dictionary base (lanzando una excepción si falta) en lugar de la implementación de la subclase .


TryGetValue ya asignará el valor predeterminado para el tipo al diccionario, por lo que puede usar:

dictionary.TryGetValue(key, out value);

y simplemente ignore el valor de retorno. Sin embargo, eso realmente solo devolverá el default(TValue) , no algún valor predeterminado personalizado (ni, más útilmente, el resultado de ejecutar un delegado). No hay nada más poderoso incorporado en el marco. Sugeriría dos métodos de extensión:

public static TValue GetValueOrDefault<TKey, TValue> (this IDictionary<TKey, TValue> dictionary, TKey key, TValue defaultValue) { TValue value; return dictionary.TryGetValue(key, out value) ? value : defaultValue; } public static TValue GetValueOrDefault<TKey, TValue> (this IDictionary<TKey, TValue> dictionary, TKey key, Func<TValue> defaultValueProvider) { TValue value; return dictionary.TryGetValue(key, out value) ? value : defaultValueProvider(); }

(Es posible que desee poner la comprobación de los argumentos, por supuesto :)