12

I have a type which I am using as key in the IDictionary. The type is as following

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();
    }
}

Now I have created a dictionary as following in my main as following

 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);

Now while debugging I found out that when emp1 is added to the collection only GetHashCode method is called of the key type, after that when emp2 is added to the collection only GetHashCode method is called again but in the case of emp3 both GetHashCode and Equals methods are called.

May be it looks too naive being asking this question but why isn't Equals method not called when eqImp2 object is added to collection. What is happening inside. Please explain.

4

5 に答える 5

8

ディクショナリおよび他のすべての同様のコンテナは、ハッシュコードを簡易チェックとして使用します。異なるハッシュコードは、2 つのオブジェクトが明らかに等しくないことを意味します。同一のハッシュコードは何の意味もありません。のドキュメントでは、GetHashCodeこの動作を次のように指定しています。

2 つのオブジェクトを比較して等しい場合、各オブジェクトの GetHashCode メソッドは同じ値を返す必要があります。ただし、2 つのオブジェクトが等しくない場合、2 つのオブジェクトの GetHashCode メソッドは異なる値を返す必要はありません。

emp1と は異なるハッシュコードをemp2生成するため、辞書を実行する必要はありませんEquals。それらが等しくないことはすでにわかっています。一方、同じハッシュコードemp2を生成すると、それらが実際に等しいかどうか、または同一のハッシュコードが単なる偶然の結果であるかどうかを明確に判断するemp3ために辞書を呼び出す必要があります。Equals

于 2013-02-20T14:10:40.597 に答える
1

この実験を続けると、Dictionary<TKey, TValue>実装に固有の動作と、実装方法に必要な動作が観察されGetHashCodeます。

まず、オブジェクトが等しいかどうかを比較するときのGetHashCodeとの役割を理解することが重要です。この質問Equalsに関する追加情報を入手できますが、ここで基本的なルールを繰り返します。

  1. メソッドは、Equalsどのオブジェクトが等しく、どのオブジェクトが等しくないかを正確に確立します。戻る前に、最終決定のために必要なすべてのチェックをこのメソッドで実行する必要があります。
  2. ハッシュ コードは、オブジェクトの値から計算される値です。通常、元のオブジェクトよりもはるかに小さく (この場合、ハッシュ コードは 4 バイトの整数です)、一意である必要はありません。ただし、元のオブジェクト自体よりも計算して相互に比較する方がはるかに高速です。
    • ハッシュ コードが一意である必要がない場合、異なるハッシュ コードは異なるオブジェクトを示します (つまりEquals、間違いなく false を返します) が、等しいハッシュ コードは何も意味しません (つまりEquals、true または false を返す可能性があります)。

値をキー オブジェクト ( IDictionary<TKey, TValue>.NET やMap<K, V>Java など) に関連付けるコレクションは、ハッシュ コードを利用して実装効率を向上させます。ただし、Object.GetHashCode具体的なドキュメントでは結果が一意である必要がないため、これらのコレクションは適切な機能のためにハッシュ コードだけに依存することはできません。2 つのオブジェクトが同じハッシュ コードを持つ場合、それらを区別できるのは への呼び出しだけです。Equalsの挿入について説明したケースは、emp3このケースに当てはまります。同じ値を挿入しようとしている場合、 [ IDictionary<TKey, TValue>.Add] メソッドは をスローする必要がArgumentExceptionあり、 を呼び出すだけでEquals、新しいキーemp3が以前に挿入された と等しいかどうかを判断できemp3ます。

追加の実装特性

特定のコレクションの実装により、GetHashCode予想よりも多くの呼び出しが発生する場合があります。たとえば、ハッシュ テーブルの内部ストレージのサイズが変更されると、実装GetHashCodeによって、コレクションに格納されているすべてのオブジェクトが呼び出される場合があります。バイナリツリーまたはB ツリーに基づくコレクションは、 1 回だけ呼び出すGetHashCode場合 (結果がツリー構造にキャッシュされている場合) や、GetHashCode挿入または検索操作のたびに複数のオブジェクトを呼び出す必要がある場合 (結果がキャッシュされていない場合) があります。

ハッシュ テーブルの実装では、モジュロ演算を使用してキーを「バケット」に配置する方法のために、GetHashCode複数のオブジェクトを呼び出す必要がある場合や、異なるハッシュ コードを持つオブジェクトを呼び出す必要がある場合もあります。Equalsこれの特定の特性は、実装ごとに異なります。

于 2013-02-20T14:39:48.140 に答える
1

あなたの例GetHashCodeでは、名前のハッシュ コードを調べます。emp3 は emp2 と同じ名前 (「vikram」) です。ハッシュコードが与えられた場合、それらは等しいため、 を使用してさらに検索しEqualsます。

于 2013-02-20T14:11:45.997 に答える
1

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 のようなツールを入手する必要があります。そうすれば、コードを見て自分で答えを見つけることができます。

于 2013-02-20T14:12:37.687 に答える
0

これは、GetHashCodeがショートカットであるためです。C# はまず、高速に実行されるはずのGetHashCodeを呼び出します。2 つのオブジェクトの HashCode が異なる場合、おそらくより高価なEqualsメソッドを呼び出す必要はありません。HashCode が同じ場合にのみ、Equalsが呼び出されます。これは、HashCode が一意であることが保証されていないためです。

于 2013-02-20T14:11:22.983 に答える