[英]Why is Equals() being not called for the all objects while adding to collection
我有一個類型,我在IDictionary中使用它作為鍵。 類型如下
public class Employee
{
public string Name { get; set; }
public int ID { get; set; }
public override bool Equals(object obj)
{
Employee emp = obj as Employee;
if (emp != null)
return emp.Name.Equals(this.Name);
return false;
}
public override int GetHashCode()
{
return this.Name.GetHashCode();
}
}
現在我已經在我的主要內容中創建了一個字典,如下所示
IDictionary<Employee, int> empCollection = new Dictionary<Employee, int>();
Employee emp1 = new Employee() { Name = "abhi", ID = 1 };
Employee emp2 = new Employee() { Name = "vikram", ID = 2 };
Employee emp3 = new Employee() { Name = "vikram", ID = 3 };
empCollection.Add(emp1, 1);
empCollection.Add(emp2, 2);
empCollection.Add(emp3, 3);
現在在調試時我發現當emp1被添加到集合中時,只調用了GetHashCode方法的密鑰類型,之后當emp2被添加到集合中時,只會再次調用GetHashCode方法,但是在emp3的情況下,GetHashCode和Equals方法都是叫做。
可能在問這個問題時看起來太天真但是為什么當eqImp2對象被添加到集合時不會調用Equals方法。 里面發生了什么。 請解釋。
字典和所有其他類似容器使用哈希碼作為快速和臟檢查:不同的哈希碼意味着兩個對象絕對不相等; 相同的哈希碼並不意味着什么。 GetHashCode
的文檔通過說明來指定此行為
如果兩個對象比較相等,則每個對象的GetHashCode方法必須返回相同的值。 但是,如果兩個對象的比較不相等,則兩個對象的GetHashCode方法不必返回不同的值。
你的emp1
和emp2
生成不同的哈希碼,所以字典不需要運行Equals
; 它已經知道它們並不平等。 另一方面, emp2
和emp3
生成相同的哈希碼,因此字典必須調用Equals
以確定它們是否確實相等,或者相同的哈希碼只是偶然的結果。
在您的示例中, GetHashCode
查看Name哈希碼。 emp3與emp2同名,(“vikram”)。 它們在給定哈希碼的情況下是相等的,因此它使用Equals
進一步查看。
emp2和emp3具有相同的密鑰。 這將導致字典中的“鍵沖突”。 它首先調用GetHashCode()並確定哈希碼是相同的。 然后通過調用Equals()確保它們是相同的。 Dictionary中的代碼是:
int num = this.comparer.GetHashCode(key) & 2147483647;
...
if (this.entries[i].hashCode == num && this.comparer.Equals(this.entries[i].key, key))
顯然,如果哈希碼不匹配,則永遠不必調用Equals。
您應該獲得像ILSpy這樣的工具,然后您可以查看代碼並自己找到答案。
如果繼續此實驗,您將觀察到一些特定於Dictionary<TKey, TValue>
實現的行為,以及由於您實現GetHashCode
的方式而需要的一些行為。
首先,在比較對象的相等性時,了解GetHashCode
和Equals
的作用非常重要。 有關此問題的其他信息,但我將在此重復基本規則:
Equals
方法確切地確定哪些對象相等以及哪些對象不相等。 在返回之前,需要在此方法中執行所有必要的檢查以進行最終確定。 Equals
肯定會返回false),但是相等的哈希碼並不意味着什么(即Equals
可以返回true或false)。 將值與關鍵對象相關聯的集合(例如,.NET中的IDictionary<TKey, TValue>
或Java中的Map<K, V>
)利用哈希碼來提高實現效率。 但是,由於Object.GetHashCode
的文檔特別不要求結果是唯一的,因此這些集合不能單獨依賴哈希代碼來獲得正確的功能。 當兩個對象具有相同的哈希碼時,只有對Equals
的調用才能區分它們。 您為插入emp3
描述的情況屬於這種情況:如果您嘗試插入相同的值,[ IDictionary<TKey, TValue>.Add
]方法需要拋出ArgumentException
,並且只有對Equals
的調用才能確定是否新密鑰emp3
等於先前插入的emp3
。
其他實施特征
特定的集合實現可能導致對GetHashCode
調用超出預期。 例如,當調整散列表的內部存儲大小時,實現可能會為集合中存儲的每個對象調用GetHashCode
。 根據集合二進制或B樹可能只調用GetHashCode
一次(如果結果是在樹結構中緩存),或者可能需要調用GetHashCode
每次插入或查找操作過程中對多個對象(如果結果沒有被高速緩存) 。
有時哈希表實現需要為多個對象調用GetHashCode
,或者甚至可能為具有不同哈希碼的對象調用Equals
,因為他們使用模運算將鍵放入“桶”中。 其具體特征因實施而異。
這是因為GetHashCode是一種快捷方式。 C#將首先調用GetHashCode ,它應該是快速執行的。 如果兩個對象具有不同的HashCodes,那么就不需要調用更為昂貴的Equals方法。 只有當它們具有相同的HashCode時,它才會調用Equals 。 這是因為HashCode不能保證是唯一的
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.