如果键不存在,则字典返回默认值

时间:2010-04-08 16:04:19

标签: c# collections dictionary

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

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)

现在,我可以为字典类编写一个扩展方法来为我做这个,但我想我可能会遗漏已经存在的东西。那么,有没有办法以一种“眼睛更容易”的方式做到这一点,而无需在字典中编写扩展方法?

4 个答案:

答案 0 :(得分:260)

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

(当然,你可能想要进行参数检查:)

答案 1 :(得分:26)

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

我希望这只是基类Dictionary类的一部分。

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对象被上传到普通Dictionary,则调用索引器将使用基本Dictionary实现(如果丢失则抛出异常),而不是子类的实现。

答案 2 :(得分:23)

我创建了一个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对象的简单装饰器和扩展方法,使其易于使用。

DefaultableDictionary允许在字典周围创建一个包装器,该字典在尝试访问不存在的键或枚举IDictionary中的所有值时提供默认值。

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

Blog post关于用法。

答案 3 :(得分:4)

不,不存在这样的事情。扩展方法是要走的路,你的名字( GetValueOrDefault )是一个不错的选择。