我发现自己现在在我的代码中经常使用当前模式
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)
现在,我可以为字典类编写一个扩展方法来为我做这个,但我想我可能会遗漏已经存在的东西。那么,有没有办法以一种“眼睛更容易”的方式做到这一点,而无需在字典中编写扩展方法?
答案 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 )是一个不错的选择。