如果键不存在,则字典返回默认值[重复]
Posted
技术标签:
【中文标题】如果键不存在,则字典返回默认值[重复]【英文标题】:Dictionary returning a default value if the key does not exist [duplicate] 【发布时间】:2011-02-05 18:52:21 【问题描述】:我发现自己现在在我的代码中经常使用当前模式
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)
现在,我可以为字典类编写一个扩展方法来为我做这件事,但我想我可能会遗漏一些已经存在的东西。那么,有没有一种方法可以在不为字典编写扩展方法的情况下以一种更“容易上手”的方式做到这一点?
【问题讨论】:
不确定为什么以下所有答案都如此复杂。只需使用合并运算符:string valFromDict = someDict["someKey"] ?? "someDefaultVal";
@DylanHunt 但这对值类型不起作用。 ;)
另请注意,使用[]
运算符还可能产生不希望的副作用,即在字典中添加不存在的值。
【参考方案1】:
TryGetValue
已经将类型的默认值分配给字典,因此您可以使用:
dictionary.TryGetValue(key, out value);
并忽略返回值。然而,真正将只返回default(TValue)
,而不是一些自定义默认值(更有用的是,执行委托的结果)。没有什么比框架更强大的了。我会建议两种扩展方法:
public static TValue GetValueOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
TValue defaultValue)
return dictionary.TryGetValue(key, out var value) ? value : defaultValue;
public static TValue GetValueOrDefault<TKey, TValue>(
this IDictionary<TKey, TValue> dictionary,
TKey key,
Func<TValue> defaultValueProvider)
return dictionary.TryGetValue(key, out var value) ? value : defaultValueProvider();
(当然,您可能希望进行参数检查:)
【讨论】:
@ProfK:无论如何,您都可以将密钥与null
进行比较;当 TKey 是不可为空的值类型时,它总是返回 false。就我个人而言,我认为我不想这样做 - 根据我的经验,空键 几乎 总是代表一个错误。
@ProfK:是的 - 为您的特定案例更改代码是有意义的,但我不想一般建议:)
谢谢。第三个参数的默认值怎么样? TValue defaultValue = default(TValue)
鉴于 Jon 的回答,我被困在如何实际调用他的扩展方法上(以前从未这样做过),所以我偶然发现了这篇 MS 文章:msdn.microsoft.com/en-us/library/bb311042.aspx。
在以后的版本中,您可以使用 System.Collections.Generic,它提供 GetValueOrDefault(key, defaultValue)。【参考方案2】:
我确实喜欢扩展方法,但是当我需要默认值时,我不时使用一个简单的类来处理字典。
我希望这只是基本 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
实现(如果丢失则抛出异常)而不是子类的实现。
【讨论】:
使用 trygetvalue 更好.. trygetvalue 不允许您指定默认值,即对于字符串值,您可能希望它返回 "" 而不是 null @roberocity 是的性能优势,请参阅:***.com/questions/9382681/… 上面的代码有一个bug。它将始终返回 0 作为默认值,因为 TryGetValue 将“t”设置为 0。更改为; T值 t; if (!TryGetValue(key, out t)) t = m_default; 返回 t; 我认为在这种情况下从Dictionary
继承是不明智的:通过使用new
关键字,您隐藏了非虚拟Item
属性。如果有人要从Dictionary
引用类型而不是DictionaryWithDefault
访问它,则将调用Dictionary
的Item
属性,而不是您的。【参考方案3】:
我创建了一个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 的用法也是如此。
【讨论】:
请在您的回答中直接提供支持 github 链接的上下文,否则可能会被删除。 如果您不删除提供清晰的链接,将会很有帮助。 我将 index getter 写为:public TValue this[TKey key] get TValue value; TryGetValue(key, out value); return value;
以避免异常处理。
我喜欢您使用扩展方法来创建默认字典,而不是要求使用您的构造函数(就像我一样)。
基于异常的流控制...哎呀!这是一个严重的反模式。请更改您的索引器实现以使用TryGetValue
而不是try ... catch
。【参考方案4】:
不,不存在这样的东西。扩展方法是要走的路,你的名字(GetValueOrDefault)是个不错的选择。
【讨论】:
以上是关于如果键不存在,则字典返回默认值[重复]的主要内容,如果未能解决你的问题,请参考以下文章