2009-07-21 47 views
10

我应该检查字典中是否存在特定的关键字,如果我确定它会在字典中添加到字典中以访问它的代码?在访问字典之前,我应该检查字典中是否存在特定的密钥?

有两种方法,我可以在字典

  1. 检查ContainsKey方法访问值。如果它返回true,那么我使用字典对象的索引器[键]进行访问。

  • TryGetValue将通过OUT参数返回true或false以及返回值。
  • (2日将执行比第一次更好,如果我想获得价值。Benchmark

    但是,如果我确信,这是进入全球词典的功能,必将有钥匙的话,我应该还是检查使用TryGetValue或不检查我应该使用索引器[]。

    或者我不应该假设,并总是检查?

    回答

    18

    使用索引如果密钥是指存在 - 如果它不存在,它会抛出一个适当的异常,这是正确的行为,如果没有钥匙的指示的错误。

    如果钥匙不存在,则使用TryGetValue,并作出相应的反应。

    (也适用关于访问共享字典安全Marc的建议。)

    10

    如果字典是全球性的(静态/共享),你应该同步访问它(这是很重要的,否则你可能会损坏它)。

    即使您的线程只有读取数据,它也需要尊重其他可能正在编辑它的线程的锁。

    但是;如果确信该项目是存在的,索引应该是罚款:

    Foo foo; 
    lock(syncLock) { 
        foo = data[key]; 
    } 
    // use foo... 
    

    否则,一个有用的模式是检查并添加相同的锁:

    Foo foo; 
    lock(syncLock) { 
        if(!data.TryGetValue(key, out foo)) { 
         foo = new Foo(key); 
         data.Add(key, foo); 
        } 
    } 
    // use foo... 
    

    在这里我们只添加项目,如果它不存在...但里面相同的锁

    +0

    不错,但我不认为这是个问题?我没有看到任何并发的参考? :) – Thorarin 2009-07-21 08:43:32

    +0

    “全球词典” - 只要给我一个给定的路径。如果我的理解不正确,OP可以忽略这个回复; -p – 2009-07-21 08:44:27

    +0

    为什么我们在从字典中读取数据时需要锁定?是否由于字典扩展/重新哈希后的一些限制? – 2015-10-08 13:48:35

    2

    总是检查。永不说永不。我假设你的应用程序不是性能至关重要的,你必须节省检查时间。

    提示:如果你决定不来检查,至少使用Debug.Assert的(dict.ContainsKey(键));这只会在调试模式下编译,您的发布版本将不包含它。这样,您至少可以在调试时进行检查。

    还有:如果可能的话,就检查它:-)

    编辑:有已经在这里存在一些误解。通过“总是检查”我不只是指在某个地方使用。正确处理异常也包括在内。所以,更确切地说:绝不要把任何事情视为理所当然,期待意料之外。通过ContainsKey进行检查或处理潜在的异常,但如果元素不包含,则执行SOMETHING。

    0

    TryGetValue是相同的代码作为由键索引它,除了前者返回的默认值(对于out参数),其中后者引发例外。使用TryGetValue,你会得到一致的检查,绝对没有性能损失。

    编辑:正如乔恩所说,如果你知道它总是有钥匙,那么你可以索引它,让它抛出适当的异常。但是,如果您可以通过向用户提供详细的消息来提供更好的上下文信息,那将是更可取的。

    0

    从表现的角度来看,有2种思路。

    1)在可能的情况下避免异常,因为异常很昂贵 - 即在尝试从字典中检索特定的密钥之前进行检查,无论是否存在。在我看来,如果有一个公平的机会,它可能不存在。这将防止相当普遍的例外。

    2)如果您确信该项目在99%的时间内存在,那么在访问它之前不要检查它是否存在。如果不存在1%的时间,将会抛出异常,但是通过不检查,您可以节省另外99%的时间。

    我说的是,如果有一个明确的优化大多数。如果某个项目存在不确定性,请在检索之前进行检查。

    0

    如果您知道字典通常包含密钥,您在访问它之前不必检查它。

    如果出现错误,并且字典中不包含应该显示的项目,可以让字典抛出异常。首先检查密钥的唯一原因是如果你想自己处理这个问题的情况,而没有得到例外。让字典抛出异常并捕获,但这是处理这种情况的完美有效方式。

    0

    我认为马克和乔恩有(如往常一样)漂亮的播种。既然你也提到了你的问题中的表现,可能值得考虑你如何锁定字典。

    简单的lock将所有读取访问序列化,如果读取频繁且写入次数相对较少,则这可能不合意。在这种情况下,使用ReaderWriterLockSlim可能会更好。缺点是代码稍微复杂一些,写入速度稍慢。

    1

    就我个人而言,我会检查关键在那里,无论你是否确定它是有的,有人可能会说这个检查是多余的,字典会抛出一个你可以捕捉的异常,但是你不应该依赖在这个例外情况下,你应该检查你自己,然后抛出你自己的异常,这意味着什么或结果对象的成功标志和理由在内......失败机制实际上是依赖于实现的。

    1

    当然,答案是“这一切都取决于情况”。您需要平衡字典中丢失密钥的风险(对于数据访问受限的小型系统,对于大型系统可以依赖的订单,对于访问相同数据的多个程序员而言较大的系统数据,特别是读/写/删除访问,涉及线程,订单无法得到保证,或者数据源于外部,读取可能失败)与风险的影响(安全关键系统,商业版本或业务系统依赖于比较有趣的东西,一次性工作和/或仅供您使用)以及对速度,尺寸和懒惰的任何要求。

    如果我正在制定一个控制铁路信号的系统,我想要避免所有可能的和不可能的错误,并避免错误处理中的错误等等(墨菲的第二定律:“什么不能去错将会出错“)。如果我为了好玩而把东西夹在一起,即使尺寸和速度都不是问题,我会对这样的东西更加轻松 - 我会想要找到有趣的东西。

    当然,有时这本身就是有趣的东西。

    相关问题