在添加键之前检查键是否存在于字典中的最佳方法

本文关键字:字典 方法 最佳 于字典 添加 检查 存在 是否 | 更新日期: 2023-09-27 18:06:51

当从字典中获取不确定是否存在的键时,通常使用TryGetValue而不是ContainsKey + get索引器,以避免两次检查键的开销。换句话说,就是:

string password;
if (accounts.TryGetValue(username, out password))
{
    // use the password
}

要优于

if (accounts.ContainsKey(username))
{
    string password = accounts[username];
}

如果我想在将一个键设置为值之前检查它是否已经存在,该怎么办?例如,我想在用新密码覆盖用户名之前检查该用户名是否存在:

if (!accounts.ContainsKey(username))
{
    accounts.Add(username, password);
}
else
{
    Console.WriteLine("Username is taken!");
}

// this doesn't exist
if (!accounts.TrySetValue(username, password))
{
    Console.WriteLine("Username is taken!");
}

是否有更多的性能替代ContainsKeyAdd做到这一点?

在添加键之前检查键是否存在于字典中的最佳方法

如果您认为插入新名称将是常见的情况,而尝试插入重复名称将是罕见的情况,您可能只想使用捕获异常的开销。

try
{
    accounts.Add(username, password);
}
catch (ArgumentException)
{
    Console.WriteLine("Username is taken!");
}

如果用一个已存在的键调用Add,将抛出一个ArgumentException。即使您有频繁的重复,这仍然可能比您的ContainsKey检查性能更高。

如果您不想重写,我认为最好编写自己的扩展方法,如TryGetValue。没有标准方法。

使用CuncurrentDictionary,它有TryAdd方法,但是你会有同步开销

所以,简单的答案——不,没有这样的方法

我倾向于根据需要编写自己的扩展。

例如,GetValueOrDefault如下:

public static V GetValueOrDefault<K, V>(this IDictionary<K, V> @this, K key, Func<V> @default)
{
    return @this.ContainsKey(key) ? @this[key] : @default();
}

可以这样使用:

var password = accounts.GetValueOrDefault(username, () => null);
if (password != null)
{
    //do stuff
}

SetValueIfExists:

public static V SetValueIfExists<K, V>(this IDictionary<K, V> @this, K key, V value)
{
    if (@this.ContainsKey(key))
    {
        @this[key] = value;
    }
}

SetValueIfNotExists:

public static V SetValueIfNotExists<K, V>(this IDictionary<K, V> @this, K key, V value)
{
    if (!@this.ContainsKey(key))
    {
        @this[key] = value;
    }
}

我知道我迟到了,但是您可以使用一个技巧,在索引器设置之前存储计数,并在索引器设置之后检查计数。如果计数相同,则覆盖键,否则添加新映射:

public static bool AddOrUpdate<TKey, TValue>(this IDictionary<TKey, TValue> 
    dictionary, TKey key, TValue value)
{
    var countBefore = dictionary.Count;
    dictionary[key] = value;
    return countBefore != dictionary.Count;
}