从字典中检索 KeyValuePair 的最有效方法

Dis*_*sti 1 c#

在我的应用程序中,我有一个Dictionary<ContainerControl, int>. 我需要检查字典中是否存在某个键,如果找到键则更改其相应的值,或者如果尚不存在则添加该键。我的字典的键是 ControlContainer 对象。我可以使用这个方法:

var dict = new Dictionary<ContainerControl, int>();

/*...*/

var c = GetControl();

if (dict.ContainsKey(c))
{
    dict[c] = dict[c] + 1;
}
else
{
    dict.Add(c, 0);
}
Run Code Online (Sandbox Code Playgroud)

但我认为这样如果键已经存在,我的字典就会迭代三次:一次在 ContainsKey 中,两次在 if 分支中。

我想知道是否有更有效的方法来做到这一点,比如

var dict = new Dictionary<ContainerControl, int>();

/*...*/

var c = GetControl();

var kvp = dict.GetKeyValuePair(c); /* there is no such function in Dictionary */

if (kvp != null)
{
    kvp.Value++;
}
else
{
    dict.Add(c, 0);
}
Run Code Online (Sandbox Code Playgroud)

使用 linq 可以做到这一点:

var kvp = dict.SingleOrDefault(x => x.Key == c);
Run Code Online (Sandbox Code Playgroud)

但性能呢?

Jon*_*eet 7

正如评论中所指出的,在字典中查找键并不意味着迭代整个字典。但在某些情况下,仍然值得尝试减少查找。

KeyValuePair<,>无论如何都是一个结构,所以如果确实GetKeyValuePair 存在,您kvp.Value++将无法编译(因为Value是只读的)并且即使它编译也不会工作(因为这对不会是字典中的“原始”)。

您可以使用TryGetValue将其减少为单个“读取”操作和单个“写入”操作:

// value will be 0 if TryGetValue returns false
if (dict.TryGetValue(c, out var value))
{
    value++;
}
dict[c] = value;
Run Code Online (Sandbox Code Playgroud)

或者更改为ConcurrentDictionary并使用AddOrUpdate在一次调用中执行更改。

  • 我预计 ConcurrentDcitionary 的同步工作将明显超过字典的第二个键查找所花费的时间,只要有一个适度合理的 gethashcode 实现即可。 (2认同)