簡體   English   中英

實現 IEqualityComparer 時 GetHashCode 是否應該檢查 null?

[英]When Implementing IEqualityComparer Should GetHashCode check for null?

在實現IEqualityComparer<Product>Product是一個類)時,ReSharper 抱怨下面的空檢查總是錯誤的:

public int GetHashCode(Product product)
{
  // Check whether the object is null. 
  if (Object.ReferenceEquals(product, null))
    return 0;

  // ... other stuff ...
}

(來自Enumerable.Except 的 MSDN VS.9 文檔的代碼示例)

ReSharper 可能是錯誤的,但是在尋找答案時,我遇到了IEqualityComparer<T>官方文檔,其中有一個示例,其中未檢查 null:

public int GetHashCode(Box bx)
{
    int hCode = bx.Height ^ bx.Length ^ bx.Width;
    return hCode.GetHashCode();
}

此外, GetHashCode()的文檔指出,當“obj 的類型是引用類型並且 obj 為 null”時,將拋出ArgumentNullException

那么,在實現IEqualityComparerGetHashCode是否應該檢查 null,如果是,它應該如何處理 null(拋出異常或返回值)?

我對 .NET 框架官方文檔最感興趣,該文檔指定了是否應檢查 null 的一種或另一種方式。

ReSharper 是錯誤的。

顯然,您編寫的代碼可以調用該特定的GetHashCode方法並傳入一個null值。 所有已知的方法都可能確保這永遠不會發生,但顯然 ReSharper 只能考慮現有代碼(模式)。

所以在這種情況下,檢查null並做“正確的事情”。


推論:如果有問題的方法是私有的,那么 ReSharper 可能會分析(盡管我不確定它會)公共代碼並驗證確實無法使用null引用調用這個特定的私有方法,但是由於它是一種公共方法,可以通過接口獲得,然后

ReSharper 是錯誤的。

文檔空值永遠不應該是可散列的,並且嘗試這樣做應該總是導致異常。

當然,你可以自由地做任何你想做的事。 如果你想創建一個空鍵有效的基於散列的結構,你可以自由地這樣做,在這種情況下你應該忽略這個警告。

ReSharper 在這里有一些特殊情況代碼。 它不會在此警告 ReferenceEquals:

if (ReferenceEquals(obj, null)) { throw new ArgumentNullException("obj"); }

它會警告這里的 ReferenceEquals:

if (ReferenceEquals(obj, null)) { return 0; }

拋出 ArgumentNullException 異常與IEqualityComparer(Of T).GetHashCode 中指定的契約一致

如果您轉到IEqualityComparer (F12) 的定義,您還會找到更多文檔:

    // Exceptions:
    //   System.ArgumentNullException:
    //     The type of obj is a reference type and obj is null.
    int GetHashCode(T obj);

所以 ReSharper 是正確的,有一些錯誤,但顯示的錯誤與您應該對代碼所做的更改不匹配。

這個問題有一些細微差別。

文檔指出IEqualityComparer<T>.GetHashCode(T)拋出null輸入 然而EqualityComparer<>.Default - 幾乎可以肯定是迄今為止最常用的實現 - 不會拋出。

顯然,一個實現不需要拋出 null 它也只是有選項。

但是,我認為任何實現都不應該在這里拋出 null,這只是令人困惑,並且可能是錯誤的來源。 異常在任何情況下都是一種痛苦,它是一種非本地控制流機制,僅在必要時才使用它們(即:不在此處)。 但另外,對於 IEqualityComparer,文檔聲明每當Equals(x, y)然后GetHashCode(x)應該等於GetHashCode(y) - 並且Equals確實允許空值,並且沒有記錄為拋出任何異常。

相等意味着哈希碼相等的不變性使得依賴於這些哈希碼的實現變得更加簡單。 有一個帶有null值的陷阱是一種設計成本,你應該避免在不需要的情況下支付。 在這里,永遠不需要。

簡而言之:

  • 不要從 GetHashCode 拋出,即使它是允許的
  • 檢查空值 Resharper 的警告是不正確的。

這樣做會導致代碼更簡單,問題更少,並且它遵循EqualityComparer<>.Default的行為,這是最常用的實現。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM