我有一个如下集合
private static readonly Dictionary<string,object> _AppCache = new Dictionary<string,object>;
然后我想知道哪一个更好用于检查是否存在密钥(我的密钥都没有空值)
_AppCache.ContainsKey("x")
_AppCache["x"] != null
此代码可能通过各种线程访问
整个代码是:
public void SetGlobalObject(string key, object value)
{
globalCacheLock.EnterWriteLock();
try
{
if (!_AppCache.ContainsKey(key))
{
_AppCache.Add(key, value);
}
}
finally
{
globalCacheLock.ExitWriteLock();
}
}
我将代码更改为使用字典将问题的重点放在Conatinskey or Indexer
答案 0 :(得分:3)
我不同意其他人使用Dictionary
的建议。但是,为了回答您的问题,我认为您应该使用ContainsKey
检查密钥是否存在有多种原因
ContainsKey
写的是_AppCache["x"] != null
正常工作,您的应用必须在未强制的假设下运行(没有值将为空)。这个假设现在可能适用,但未来的维护者可能不知道或理解这个关键假设,导致不直观的错误ContainsKey
的处理略少,尽管这不是很重要这两个选项都不是线程安全的,所以这不是决定因素。为此,您需要使用锁定,或使用ConcurrentDictionary
。
如果您转到Dictionary
(根据您的问题更新),答案更有利于ContainsKey
。如果使用了index选项,则必须捕获异常以检测该键是否不在Dictionary中。 ContainsKey
在您的代码中会更直接。
当密钥位于Dictionary
时,ContainsKey
的效率会略高一些。这两个选项首先调用内部方法FindEntry。在ContainsKey
的情况下,它只返回结果。对于index选项,它还必须检索该值。如果密钥不在字典中,则索引选项的效率会相当低,因为它会抛出异常。
答案 1 :(得分:1)
您显然正在检查该密钥的存在。在这种情况下,如果密钥不存在,_AppCache["x"] != null
将为您提供KeyNotFoundException
,这可能并不理想。如果您确实想要检查密钥是否存在,而不通过检查生成异常,则必须使用_AppCache.ContainsKey("x")
。为了检查密钥是否存在于字典或散列表中,我会坚持使用ContainsKey
。如果!= null
更快,那么性能上的任何差异都会被额外的代码所抵消,如果密钥确实不存在则会处理异常。
实际上,_AppCache["x"] != null
不检查密钥是否存在,它正在检查,给定密钥&#34; x&#34;存在,关联的值是否为空。
无论哪种方式(尽管完成不同的任务)都能为您提供线程安全方面的任何优势。
所有这一切都适用于ConcurrentDictionary
- 线程安全没有区别,这两种方式可以完成不同的事情,使用!=null
进行检查时可能获得的任何增益都会被处理异常的其他代码所抵消。因此,请使用ContainsKey
。
答案 2 :(得分:1)
如果你担心线程安全,你应该看看ConcurrentDictionary类。
如果您不想使用ConcurrentDictionary,则必须确保同步对常规Dictionary<K,V>
实例的访问。这意味着,通过锁定每次写入和读取操作,确保没有2个线程可以多次访问您的字典。
例如,如果您想以线程安全的方式向常规Dictionary添加内容,则必须这样做:
private readonly object _sync = new object();
// ...
lock( _sync )
{
if( _dictionary.ContainsKey(someKey) == false )
{
_dictionary.Add(someKey, somevalue);
}
}
自从引入通用Dictionary<K,V>
类以来,你不应该继续使用Hashtable,因此在.NET 2.0中引入了类型安全的替代方案
使用Dictionary<K,V>
时有一点需要注意:当您想要检索与给定键关联的值时,如果没有该指定键的条目,Dictionary将抛出异常,而Hashtable将返回null在那种情况下。
答案 3 :(得分:1)
您应该使用ConcurrentDictionary而不是字典,这本身就是线程安全的。因此,您不需要锁定(通常*)可以提高性能,因为锁定机制相当昂贵。
现在,仅检查条目是否存在我建议使用ContainsKey,而不管您使用哪个(并发)词典:
_AppCache.ContainsKey(key)
但是你可以使用GetOrAdd使用“并发字典”一步完成两个步骤:
_AppCache.GetOrAdd(key, value);
您既不需要锁也不会采取行动:
public void SetGlobalObject(string key, object value)
{
_AppCache.GetOrAdd(key, value);
}
这不仅(可能*)表现更好,但我认为它表达了你的意图更清晰,更少杂乱。
(*)使用&#34;可能&#34;和&#34;一般&#34;这里要强调的是,这些数据结构确实具有大量的性能优化,但必须始终测量您的特定情况的性能。