Jam*_* Ko 10 c# performance dictionary hashtable data-structures
从词典中获取一个你不确定存在的键时,你通常会使用TryGetValue而不是ContainsKey+ get索引器来避免两次检查键的开销.换句话说,这个:
string password;
if (accounts.TryGetValue(username, out password))
{
// use the password
}
Run Code Online (Sandbox Code Playgroud)
会更喜欢这个:
if (accounts.ContainsKey(username))
{
string password = accounts[username];
}
Run Code Online (Sandbox Code Playgroud)
如果我想在将其设置为值之前检查密钥是否已存在,该怎么办?例如,我想在用新密码覆盖之前检查用户名是否存在:
if (!accounts.ContainsKey(username))
{
accounts.Add(username, password);
}
else
{
Console.WriteLine("Username is taken!");
}
Run Code Online (Sandbox Code Playgroud)
VS
// this doesn't exist
if (!accounts.TrySetValue(username, password))
{
Console.WriteLine("Username is taken!");
}
Run Code Online (Sandbox Code Playgroud)
是否有更高性能的替代方案,ContainsKey并且Add这样做?
如果您认为插入新名称是常见情况,而尝试插入重复名称是罕见情况,您可能只想利用捕获异常的开销。
try
{
accounts.Add(username, password);
}
catch (ArgumentException)
{
Console.WriteLine("Username is taken!");
}
Run Code Online (Sandbox Code Playgroud)
如果您Add使用现有密钥调用ArgumentException,则会抛出 a 。即使您经常有重复项,这仍然可能比您的ContainsKey检查性能更高。
我倾向于根据需要编写自己的扩展。
例如,GetValueOrDefault像这样:
public static V GetValueOrDefault<K, V>(this IDictionary<K, V> @this, K key, Func<V> @default)
{
return @this.ContainsKey(key) ? @this[key] : @default();
}
Run Code Online (Sandbox Code Playgroud)
它可以这样使用:
var password = accounts.GetValueOrDefault(username, () => null);
if (password != null)
{
//do stuff
}
Run Code Online (Sandbox Code Playgroud)
或者SetValueIfExists:
public static V SetValueIfExists<K, V>(this IDictionary<K, V> @this, K key, V value)
{
if (@this.ContainsKey(key))
{
@this[key] = value;
}
}
Run Code Online (Sandbox Code Playgroud)
或者SetValueIfNotExists:
public static V SetValueIfNotExists<K, V>(this IDictionary<K, V> @this, K key, V value)
{
if (!@this.ContainsKey(key))
{
@this[key] = value;
}
}
Run Code Online (Sandbox Code Playgroud)