2015-05-10 72 views
4

給定一個C#中的對象實例,如何確定該對象是否具有值語義?換句話說,我想保證我的API中使用的對象適合用作字典鍵。我在想這樣的事情:確定一個實例已覆蓋GetHashCode和Equals?

var type = instance.GetType(); 
var d1 = FormatterServices.GetUninitializedObject(type); 
var d2 = FormatterServices.GetUninitializedObject(type); 
Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode()); 

你對這種方法有什麼看法?

+0

你可以把基於'IEquatable '通用約束。 – MarcinJuraszek

+1

具有默認引用等式的類型非常適合Dictionary鍵。 –

+1

更簡單:'instance.GetHashCode()== RuntimeHelpers.GetHashCode(instance)'。它告訴返回的哈希碼是否與未重寫的'對象'實現使用的哈希碼相同。不過,對於值類型來說,這並不太有意義,但應該可以工作(新框的哈希代碼)。請注意,哈希碼相同可能是一個「意外」(偶然)。 –

回答

3

FormatterServices.GetUninitializedObject可以使對象處於無效狀態;它打破了只讀字段的保證分配等任何假設字段不會是null的代碼將會中斷。我不會使用它。

您可以檢查GetHashCodeEquals是否通過反射覆蓋,但這還不夠。您可以重寫方法調用基類方法。這不算作價值語義。

Btw值的語義並不意味着相同的哈希碼。這也可能是一場碰撞。值語義意味着兩個具有equals屬性的對象應該返回相同的哈希碼以及equals方法應該評估爲true。

我建議你創建一個實例,指定一些屬性,克隆它;現在兩個哈希碼應該相等,並且調用object.Equals(original, clone)應該評估爲true。

+0

我同意你的所有答案,但我想強調創建一個實例,分配一些屬性,克隆,然後比較hashcode是不可靠的。根據哈希碼的實現方式,對於某些哈希碼,破壞的實現仍然可以正確運行(如果你不幸,那些將是最終測試的)。 –

+0

@Asad好點;如果散列碼的實現被破壞,那麼在寫這個方法之前,OP應該修正它。此外,我不確定編寫此測試是否明智。當他決定添加一個類型作爲字典的關鍵字時,他可以確保該類型具有值語義。國際海事組織無需爲此進行測試。我們一直這樣做,從來沒有寫過檢查價值語義的測試。 –

+0

OP正在嘗試測試某些API的使用者是否已經在作爲OP代碼的類型參數傳遞的類型中正確實現了值語義。如果OP壞了,我認爲OP沒有辦法解決它。我的觀點是,OP沒有萬無一失的方法來檢測哈希是否正確實現,所以最好在文檔中聲明「實現哈希和等同性,否則」,並將其留在那裏。 –

3

可以測試實施的Equals()GetHashCode()本:

s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType() 

或者說每@ HVD的建議:

s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object) 

有的一些對象S,如果GetHashCode()不是由它的類型實現,這將是錯誤的,否則是真的。

需要注意的一件事是,這不會保護Equals()GetHashCode()的糟糕實施 - 即使實施是public override int GetHashCode() { },這也會評估爲真。由於缺點,我傾向於記錄你的類型(「這個類型應該/不應該用於字典鍵......」),因爲這不是你最終可以依賴的東西。如果Equals()GetHashCode()的實現有缺陷,但它會通過此測試但仍存在運行時錯誤。

+0

你可能想''= typeof(object)',而不是'== s.GetType()'。不同的基類可能已經以合理的方式覆蓋了該方法。 – hvd

+0

@ hvd這是一個很好的想法,雖然不會爲另一個交易一個「可能的情況」嗎? – jdphenix

+0

是的,我已經評論了爲什麼我認爲OP應該完全放棄這種方法的問題。 :)但是,如果OP想要繼續它,我認爲對待基類覆蓋可能具有價值語義更接近OP要求的內容。 – hvd

1

你可以看到,如果一個對象使用的相應MethodInfo的​​屬性定義了自己的EqualsGetHashCode

bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type; 
+0

這不算作價值語義。重寫的方法可以簡單地調用基本實現(可以使用參考比較)。 –

+0

@SriramSakthivel - 是的,這隻能回答標題中的問題。 – Lee

相關問題