代码之家  ›  专栏  ›  技术社区  ›  wasatz

如果键不存在,则返回默认值的字典[重复]

  •  196
  • wasatz  · 技术社区  · 14 年前

    我发现我现在经常在代码中使用当前的模式

    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
    

    或者有时

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

    这两种方式都很迂回。我真正想要的是

    dictionary.GetValueOrDefault(key)
    

    现在,我可以为Dictionary类编写一个扩展方法,它可以为我实现这一点,但是我发现我可能缺少已经存在的东西。那么,有没有一种方法可以更容易地做到这一点,而不需要为字典编写扩展方法呢?

    4 回复  |  直到 9 年前
        1
  •  255
  •   Jon Skeet    14 年前

    TryGetValue 将已经为该类型分配默认值到字典,因此您只能使用:

    dictionary.TryGetValue(key, out value);
    

    忽略返回值。但是,那真的 就回来 default(TValue) 不是某些自定义默认值(更有用的是,也不是执行委托的结果)。框架中没有更强大的功能。我建议使用两种扩展方法:

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

    (当然,您可能想让参数签入:)

        2
  •  25
  •   ErikE Russ Cam    9 年前

    我知道这是一篇老文章,我很喜欢扩展方法,但是这里有一个简单的类,当我需要默认值时,我经常使用它来处理字典。

    我希望这只是基本字典类的一部分。

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

    但是要小心。通过子类化和使用 new (自 override 在本机上不可用 Dictionary 类型),如果 DictionaryWithDefault 对象向上转换为平面 词典 ,调用索引器将使用基 词典 实现(如果缺少则引发异常)而不是子类的实现。

        3
  •  22
  •   sehe    13 年前

    我创造了一个 DefaultableDictionary 做你所要求的!

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

    这个项目是IDictionary对象的一个简单的修饰器,也是一个易于使用的扩展方法。

    当试图访问不存在的键或枚举IDictionary中的所有值时,DefaultableDictionary将允许围绕提供默认值的字典创建包装。

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

    Blog post 在使用上也是如此。

        4
  •  4
  •   Patrick Karcher    14 年前

    不,不存在这样的情况。扩展方法是一种方法,它的名称是( 获取值或默认值 )是个不错的选择。