2009-07-21 83 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

    當然,答案是「這一切都取決於情況」。您需要平衡字典中丟失密鑰的風險(對於數據訪問受限的小型系統,對於大型系統可以依賴的訂單,對於訪問相同數據的多個程序員而言較大的系統數據,特別是讀/寫/刪除訪問,涉及線程,訂單無法得到保證,或者數據源於外部,讀取可能失敗)與風險的影響(安全關鍵系統,商業版本或業務系統依賴於比較有趣的東西,一次性工作和/或僅供您使用)以及對速度,尺寸和懶惰的任何要求。

    如果我正在制定一個控制鐵路信號的系統,我想要避免所有可能的和不可能的錯誤,並避免錯誤處理中的錯誤等等(墨菲的第二定律:「什麼不能去錯將會出錯「)。如果我爲了好玩而把東西夾在一起,即使尺寸和速度都不是問題,我會對這樣的東西更加輕鬆 - 我會想要找到有趣的東西。

    當然,有時這本身就是有趣的東西。

    相關問題