Dizionario che restituisce un valore predefinito se la chiave non esiste

Al giorno d’oggi mi trovo a usare lo schema corrente abbastanza spesso nel mio codice

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

O a volte

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

Entrambi questi modi si sentono abbastanza rotondi. Quello che vorrei davvero è qualcosa di simile

 dictionary.GetValueOrDefault(key) 

Ora, potrei scrivere un metodo di estensione per la class del dizionario che fa questo per me, ma ho capito che potrei mancare qualcosa che esiste già. Quindi, c’è un modo per farlo in un modo che sia più “facile per gli occhi” senza scrivere un metodo di estensione al dizionario?

    TryGetValue assegnerà già il valore predefinito per il tipo al dizionario, quindi puoi semplicemente utilizzare:

     dictionary.TryGetValue(key, out value); 

    e basta ignorare il valore di ritorno. Tuttavia, ciò restituirà solo il default(TValue) , non un valore predefinito personalizzato (né, più, il risultato dell’esecuzione di un delegato). Non c’è niente di più potente incorporato nel framework. Suggerirei due metodi di estensione:

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

    (Si consiglia di inserire il controllo degli argomenti, ovviamente 🙂

    So che questo è un vecchio post e preferisco i metodi di estensione, ma ecco una semplice class che uso di volta in volta per gestire i dizionari quando ho bisogno di valori predefiniti.

    Vorrei che questo fosse solo parte della class base del dizionario.

     public class DictionaryWithDefault : Dictionary { 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; } } } 

    Attenzione, comunque. Con sottoclassi e utilizzo di new (poiché override non è disponibile nel tipo di Dictionary nativo), se un object DictionaryWithDefault viene aggiornato a un Dictionary normale, chiamando l’indicizzatore verrà utilizzata l’implementazione di base del Dictionary (generando un’eccezione se mancante) anziché l’implementazione della sottoclass .

    Ho creato un DefaultableDictionary per fare esattamente quello che stai chiedendo!

     using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; namespace DefaultableDictionary { public class DefaultableDictionary : IDictionary { private readonly IDictionary dictionary; private readonly TValue defaultValue; public DefaultableDictionary(IDictionary dictionary, TValue defaultValue) { this.dictionary = dictionary; this.defaultValue = defaultValue; } public IEnumerator> GetEnumerator() { return dictionary.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public void Add(KeyValuePair item) { dictionary.Add(item); } public void Clear() { dictionary.Clear(); } public bool Contains(KeyValuePair item) { return dictionary.Contains(item); } public void CopyTo(KeyValuePair[] array, int arrayIndex) { dictionary.CopyTo(array, arrayIndex); } public bool Remove(KeyValuePair 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 Keys { get { return dictionary.Keys; } } public ICollection Values { get { var values = new List(dictionary.Values) { defaultValue }; return values; } } } public static class DefaultableDictionaryExtensions { public static IDictionary WithDefaultValue(this IDictionary dictionary, TValue defaultValue ) { return new DefaultableDictionary(dictionary, defaultValue); } } } 

    Questo progetto è un semplice decoratore per un object IDictionary e un metodo di estensione per renderlo facile da usare.

    Il DefaultableDictionary consentirà di creare un wrapper attorno a un dizionario che fornisce un valore predefinito quando si tenta di accedere a una chiave che non esiste o che enumera attraverso tutti i valori in un IDictionary.

    Esempio: var dictionary = new Dictionary().WithDefaultValue(5);

    Post sul blog anche sull’utilizzo.

    No, non esiste niente del genere. Il metodo di estensione è la strada da percorrere e il tuo nome ( GetValueOrDefault ) è una scelta abbastanza buona.