关于c#:如果密钥不存在,则返回默认值

Dictionary returning a default value if the key does not exist

本问题已经有最佳答案,请猛点这里访问。

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

1
2
3
4
5
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

或者有时

1
2
3
4
5
6
7
var dictionary = new Dictionary<type, IList<othertype>>();
// Add stuff to dictionary

IList<othertype> somethingElse;
if(!dictionary.TryGetValue(key, out somethingElse) {
    somethingElse = new List<othertype>();
}

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

1
dictionary.GetValueOrDefault(key)

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


TryGetValue已经将该类型的默认值赋给字典,因此您只需使用:

1
dictionary.TryGetValue(key, out value);

忽略返回值。但是,这实际上只是返回default(TValue),而不是一些自定义默认值(更有用的是,执行委托的结果)。框架中没有更强大的功能。我建议使用两种扩展方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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进行子类化和使用(因为本地Dictionary类型上没有override),如果DictionaryWithDefault对象向上转换为普通Dictionary,调用索引器将使用基本Dictionary实现(如果缺少则抛出异常)而不是子类的实现。


我创建了一个默认字典来完全满足您的要求!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
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().WithDefaultValue(5);

关于使用情况的博客文章。


不,不存在这样的情况。扩展方法是一种可行的方法,您的名称(getValueOrDefault)是一个不错的选择。