Mengapa penting untuk mengganti GetHashCode ketika metode Equals diganti?

1445

Diberi kelas berikut

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null) 
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }
}

Saya telah mengganti Equalsmetode karena Foomewakili baris untuk Footabel s. Yang merupakan metode yang disukai untuk menimpaGetHashCode ?

Mengapa penting untuk mengganti GetHashCode?

David Basarab
sumber
36
Sangat penting untuk mengimplementasikan kode equals dan gethash, karena tabrakan, khususnya saat menggunakan kamus. jika dua objek mengembalikan kode hash yang sama, mereka dimasukkan dalam kamus dengan rantai. Saat mengakses item sama dengan metode yang digunakan.
DarthVader

Jawaban:

1320

Ya, penting jika item Anda akan digunakan sebagai kunci dalam kamus, atau HashSet<T>, dll - karena ini digunakan (tanpa adanya kebiasaan IEqualityComparer<T>) untuk mengelompokkan item ke dalam ember. Jika kode hash untuk dua item tidak cocok, mereka mungkin tidak pernah dianggap sama ( Persamaan tidak akan pernah disebut).

Metode GetHashCode () harus mencerminkan Equalslogika; aturannya adalah:

  • jika dua hal sama ( Equals(...) == true) maka mereka harus mengembalikan nilai yang sama untukGetHashCode()
  • jika GetHashCode()sama, tidak perlu bagi mereka untuk menjadi sama; ini adalah tabrakan, dan Equalsakan dipanggil untuk melihat apakah itu persamaan nyata atau tidak.

Dalam hal ini, sepertinya " return FooId;" merupakan GetHashCode()implementasi yang sesuai . Jika Anda menguji beberapa properti, adalah umum untuk menggabungkannya menggunakan kode seperti di bawah ini, untuk mengurangi tabrakan diagonal (yaitu sehingga new Foo(3,5)memiliki kode hash yang berbeda new Foo(5,3)):

unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)
    int hash = 13;
    hash = (hash * 7) + field1.GetHashCode();
    hash = (hash * 7) + field2.GetHashCode();
    ...
    return hash;
}

Oh - untuk kenyamanan, Anda mungkin juga mempertimbangkan penyediaan ==dan !=operator saat mengganti Equalsdan GetHashCode.


Peragaan tentang apa yang terjadi ketika Anda melakukan kesalahan ini ada di sini .

Marc Gravell
sumber
49
Bisakah saya bertanya apakah Anda mengalikan faktor-faktor tersebut?
Leandro López
22
Sebenarnya, saya mungkin bisa kehilangan salah satunya; intinya adalah mencoba untuk meminimalkan jumlah tabrakan - sehingga objek {1,0,0} memiliki hash yang berbeda dengan {0,1,0} dan {0,0,1} (jika Anda melihat apa yang saya maksud ),
Marc Gravell
13
Saya mengubah nomor untuk membuatnya lebih jelas (dan menambahkan seed). Beberapa kode menggunakan angka yang berbeda - misalnya kompiler C # (untuk tipe anonim) menggunakan seed 0x51ed270b dan faktor -1521134295.
Marc Gravell
76
@Leandro López: Biasanya faktor dipilih menjadi bilangan prima karena membuat jumlah tabrakan lebih kecil.
Andrei Rînea
29
"Oh - untuk kenyamanan, Anda mungkin juga mempertimbangkan untuk menyediakan operator == dan! = Saat menimpa Equals dan GethashCode.": Microsoft mencegah operator pelaksana == untuk objek yang tidak dapat diubah - msdn.microsoft.com/en-us/library/ ms173147.aspx - "Ini bukan ide yang baik untuk menimpa operator == dalam tipe yang tidak dapat diubah."
antiduh
137

Ini sebenarnya sangat sulit untuk diimplementasikan GetHashCode()dengan benar karena, di samping aturan yang telah disebutkan Marc, kode hash tidak boleh berubah selama masa objek. Oleh karena itu bidang yang digunakan untuk menghitung kode hash harus tidak berubah.

Saya akhirnya menemukan solusi untuk masalah ini ketika saya bekerja dengan NHibernate. Pendekatan saya adalah menghitung kode hash dari ID objek. ID hanya dapat ditetapkan melalui konstruktor jadi jika Anda ingin mengubah ID, yang sangat tidak mungkin, Anda harus membuat objek baru yang memiliki ID baru dan karenanya kode hash baru. Pendekatan ini bekerja paling baik dengan GUID karena Anda dapat memberikan konstruktor tanpa parameter yang secara acak menghasilkan ID.

Albic
sumber
20
@vanja. Saya percaya itu ada hubungannya dengan: jika Anda menambahkan objek ke kamus dan kemudian mengubah id objek, ketika mengambil nanti Anda akan menggunakan hash yang berbeda untuk mengambilnya sehingga Anda tidak akan pernah mendapatkannya dari kamus.
ANeves
74
Dokumentasi Microsoft tentang fungsi GetHashCode () tidak menyatakan atau menyiratkan bahwa hash objek harus tetap konsisten selama masa pakainya. Bahkan, ia secara khusus menjelaskan satu kasus yang diizinkan di mana ia mungkin tidak : "Metode GetHashCode untuk suatu objek harus secara konsisten mengembalikan kode hash yang sama selama tidak ada modifikasi pada keadaan objek yang menentukan nilai kembali metode Persamaan objek objek. . "
PeterAllenWebb
37
"kode hash tidak boleh berubah selama masa objek" - itu tidak benar.
kiamat
7
Cara yang lebih baik untuk mengatakannya adalah "kode hash (atau evaulation of equals) harus berubah selama periode objek digunakan sebagai kunci untuk koleksi" Jadi, jika Anda menambahkan objek ke kamus sebagai kunci, Anda harus memastikan bahwa GetHashCode dan Equals tidak akan mengubah output mereka untuk input yang diberikan sampai Anda menghapus objek dari kamus.
Scott Chamberlain
11
@ScottChamberlain Saya pikir Anda lupa TIDAK dalam komentar Anda, itu seharusnya: "kode hash (atau evaulation of equals) TIDAK boleh berubah selama periode objek digunakan sebagai kunci untuk koleksi". Baik?
Stan Prokop
57

Dengan mengesampingkan Sama Anda pada dasarnya menyatakan bahwa Anda adalah orang yang lebih tahu bagaimana membandingkan dua contoh dari jenis yang diberikan, sehingga Anda cenderung menjadi kandidat terbaik untuk memberikan kode hash terbaik.

Ini adalah contoh bagaimana ReSharper menulis fungsi GetHashCode () untuk Anda:

public override int GetHashCode()
{
    unchecked
    {
        var result = 0;
        result = (result * 397) ^ m_someVar1;
        result = (result * 397) ^ m_someVar2;
        result = (result * 397) ^ m_someVar3;
        result = (result * 397) ^ m_someVar4;
        return result;
    }
}

Seperti yang Anda lihat, coba tebak kode hash yang baik berdasarkan semua bidang di kelas, tetapi karena Anda tahu domain objek atau rentang nilai, Anda masih bisa memberikan yang lebih baik.

Perangkap
sumber
7
Tidakkah ini selalu menghasilkan nol? Mungkin harus menginisialisasi hasil ke 1! Juga membutuhkan beberapa semi-titik dua.
Sam Mackrill
16
Anda mengetahui apa yang dilakukan operator XOR (^)?
Stephen Drew
1
Seperti yang saya katakan, inilah yang ditulis R # untuk Anda (setidaknya itulah yang dilakukan pada 2008) ketika diminta. Jelas, cuplikan ini dimaksudkan untuk diubah oleh programmer dengan beberapa cara. Adapun semi-titik dua yang hilang ... ya, sepertinya saya meninggalkan mereka ketika saya menyalin-tempel kode dari pilihan wilayah di Visual Studio. Saya juga berpikir orang akan mencari tahu keduanya.
Perangkap
3
@ SamMackrill Saya telah menambahkan di titik koma yang hilang.
Matthew Murdoch
5
@ SamMackrill Tidak, itu tidak akan selalu mengembalikan 0. 0 ^ a = a, jadi 0 ^ m_someVar1 = m_someVar1. Dia mungkin juga mengatur nilai awal resultuntuk m_someVar1.
Millie Smith
41

Tolong jangan lupa untuk memeriksa parameter obj nullsaat menimpa Equals(). Dan juga membandingkan tipenya.

public override bool Equals(object obj)
{
    Foo fooItem = obj as Foo;

    if (fooItem == null)
    {
       return false;
    }

    return fooItem.FooId == this.FooId;
}

Alasan untuk ini adalah: Equalsharus mengembalikan false jika dibandingkan dengan null. Lihat juga http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

huha
sumber
6
Pemeriksaan tipe ini akan gagal dalam situasi di mana subclass merujuk pada metode superclass Equals sebagai bagian dari perbandingannya sendiri (yaitu basis. Persamaan (obj)) - harus digunakan sebagai gantinya
sweetfa
@sweetfa: Tergantung bagaimana metode Equals dari subclass diimplementasikan. Bisa juga memanggil base.Equals ((BaseType) obj)) yang akan berfungsi dengan baik.
huha
2
Tidak, itu tidak akan: msdn.microsoft.com/en-us/library/system.object.gettype.aspx . Dan selain itu, implementasi metode tidak boleh gagal atau berhasil tergantung pada cara namanya. Jika runtime-type suatu objek adalah subclass dari beberapa baseclass maka Equals () dari baseclass harus mengembalikan true jika objmemang sama dengan thistidak peduli berapa Equals () dari baseclass dipanggil.
Jupiter
2
Memindahkan fooItemke atas dan kemudian memeriksa untuk null akan berkinerja lebih baik dalam kasus null atau tipe yang salah.
IllidanS4 ingin Monica kembali
1
@ 40Alpha Yah, ya, maka obj as Footidak valid.
IllidanS4 ingin Monica kembali
35

Bagaimana tentang:

public override int GetHashCode()
{
    return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}

Dengan asumsi kinerja bukan masalah :)

Ludmil Tinkov
sumber
1
erm - tetapi Anda mengembalikan string untuk metode berbasis int; _0
jim tollan
32
Tidak, dia memanggil GetHashCode () dari objek String, yang mengembalikan int.
Richard Clayton
3
Saya tidak berharap ini secepat yang saya inginkan, tidak hanya untuk tinju yang terlibat untuk jenis nilai, tetapi juga untuk kinerja string.Format. Salah satu culun lain yang saya lihat adalah new { prop1, prop2, prop3 }.GetHashCode(). Tidak bisa berkomentar mana yang lebih lambat di antara keduanya. Jangan menyalahgunakan alat.
nawfal
16
Ini akan mengembalikan true untuk { prop1="_X", prop2="Y", prop3="Z" }dan { prop1="", prop2="X_Y", prop3="Z_" }. Anda mungkin tidak menginginkan itu.
voetsjoeba
2
Yap, Anda selalu dapat mengganti simbol garis bawah dengan sesuatu yang tidak terlalu umum (misalnya •, ▲, ►, ◄, ☺, ☻) dan berharap pengguna Anda tidak akan menggunakan simbol-simbol ini ... :)
Ludmil Tinkov
13

Kami memiliki dua masalah untuk diatasi.

  1. Anda tidak dapat memberikan yang masuk akal GetHashCode()jika bidang apa pun di objek dapat diubah. Juga sering suatu objek tidak akan pernah digunakan dalam koleksi yang bergantung pada GetHashCode(). Jadi biaya implementasi GetHashCode()sering tidak sepadan, atau tidak mungkin.

  2. Jika seseorang meletakkan objek Anda dalam koleksi yang memanggil GetHashCode()dan Anda telah menimpanya Equals()tanpa juga membuat GetHashCode()perilaku dengan cara yang benar, orang itu mungkin menghabiskan waktu berhari-hari melacak masalah.

Karena itu secara default saya lakukan.

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        if (fooItem == null)
        {
           return false;
        }

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Some comment to explain if there is a real problem with providing GetHashCode() 
        // or if I just don't see a need for it for the given class
        throw new Exception("Sorry I don't know what GetHashCode should do for this class");
    }
}
Ian Ringrose
sumber
5
Melempar pengecualian dari GetHashCode adalah pelanggaran terhadap kontrak Obyek. Tidak ada kesulitan mendefinisikan GetHashCodefungsi sedemikian rupa sehingga setiap dua objek yang sama mengembalikan kode hash yang sama; return 24601;dan return 8675309;keduanya akan menjadi implementasi yang valid dari GetHashCode. Performa Dictionaryhanya akan layak ketika jumlah item kecil, dan akan menjadi sangat buruk jika jumlah item menjadi besar, tetapi itu akan berfungsi dengan benar dalam hal apa pun.
supercat
2
@supercat, Tidak mungkin untuk mengimplementasikan GetHashCode dengan cara yang masuk akal jika bidang identifikasi dalam objek dapat berubah, karena kode hash tidak boleh berubah. Melakukan apa yang Anda katakan dapat menyebabkan seseorang harus menghabiskan waktu berhari-hari melacak masalah kinerja, kemudian berminggu-minggu pada sistem besar yang dirancang ulang untuk menghapus penggunaan kamus.
Ian Ringrose
2
Saya biasa melakukan sesuatu seperti ini untuk semua kelas yang saya definisikan membutuhkan Equals (), dan di mana saya sepenuhnya yakin saya tidak akan pernah menggunakan objek itu sebagai kunci dalam koleksi. Lalu suatu hari sebuah program di mana saya menggunakan objek seperti itu sebagai input ke kontrol DevExpress XtraGrid jatuh. Ternyata XtraGrid, di belakang saya, sedang membuat HashTable atau sesuatu berdasarkan objek saya. Saya berdebat dengan DevExpress mendukung orang-orang tentang ini. Saya mengatakan itu tidak pintar bahwa mereka mendasarkan fungsionalitas dan keandalan komponen mereka pada implementasi metode yang tidak dikenal pelanggan.
RenniePet
Orang-orang DevExpress agak snarky, pada dasarnya mengatakan saya harus menjadi idiot untuk melemparkan pengecualian dalam metode GetHashCode (). Saya masih berpikir mereka harus menemukan metode alternatif untuk melakukan apa yang mereka lakukan - Saya ingat Marc Gravell pada utas berbeda yang menggambarkan bagaimana dia membangun kamus objek yang berubah-ubah tanpa bergantung pada GetHashCode () - tidak dapat mengingat bagaimana dia melakukannya meskipun.
RenniePet
4
@RenniePet, harus lebih baik naksir karena melemparkan pengecualian, kemudian memiliki sangat sulit untuk menemukan bug karena implementasi yang tidak valid.
Ian Ringrose
12

Itu karena kerangka kerja mengharuskan dua objek yang sama harus memiliki kode hash yang sama. Jika Anda mengganti metode equals untuk melakukan perbandingan khusus dua objek dan kedua objek dianggap sama dengan metode tersebut, maka kode hash dari kedua objek juga harus sama. (Kamus dan Hashtable mengandalkan prinsip ini).

kemiller2002
sumber
11

Tambahkan saja jawaban di atas:

Jika Anda tidak menimpa Sama dengan maka perilaku default adalah bahwa referensi objek dibandingkan. Hal yang sama berlaku untuk kode hash - penerapan standar biasanya didasarkan pada alamat memori referensi. Karena Anda mengganti Equals, artinya perilaku yang benar adalah membandingkan apa pun yang Anda implementasikan pada Equals dan bukan referensi, jadi Anda harus melakukan hal yang sama untuk kode hash.

Klien kelas Anda akan mengharapkan kode hash memiliki logika yang mirip dengan metode equals, misalnya metode LINQ yang menggunakan IEqualityComparer pertama membandingkan kode hash dan hanya jika mereka sama mereka akan membandingkan metode Equals () yang mungkin lebih mahal untuk menjalankan, jika kita tidak mengimplementasikan kode hash, objek yang sama mungkin akan memiliki kode hash yang berbeda (karena mereka memiliki alamat memori yang berbeda) dan akan ditentukan secara salah karena tidak sama (Equals () bahkan tidak akan mengenai).

Selain itu, kecuali masalah yang Anda mungkin tidak dapat menemukan objek Anda jika Anda menggunakannya dalam kamus (karena dimasukkan oleh satu kode hash dan ketika Anda mencarinya, kode hash default mungkin akan berbeda dan lagi sama dengan Equals () bahkan tidak akan dipanggil, seperti yang dijelaskan Marc Gravell dalam jawabannya, Anda juga memperkenalkan pelanggaran kamus atau konsep hashset yang seharusnya tidak mengizinkan kunci identik - Anda sudah menyatakan bahwa benda-benda itu pada dasarnya sama ketika Anda mengesampingkan Persamaan sehingga Anda tidak tidak ingin keduanya sebagai kunci yang berbeda pada struktur data yang dianggap memiliki kunci unik. Tetapi karena mereka memiliki kode hash yang berbeda, kunci "yang sama" akan dimasukkan sebagai yang berbeda.

BornToCode
sumber
8

Kode Hash digunakan untuk koleksi berbasis hash seperti Kamus, Hashtable, HashSet dll. Tujuan kode ini adalah untuk dengan cepat mengurutkan objek tertentu dengan memasukkannya ke dalam grup tertentu (bucket). Pre-sorting ini sangat membantu dalam menemukan objek ini ketika Anda perlu mengambilnya kembali dari koleksi hash karena kode harus mencari objek Anda hanya dalam satu ember, bukan di semua objek yang dikandungnya. Distribusi kode hash yang lebih baik (keunikan yang lebih baik) semakin cepat pengambilan. Dalam situasi ideal di mana setiap objek memiliki kode hash unik, menemukan itu adalah operasi O (1). Dalam kebanyakan kasus mendekati O (1).

Maciej
sumber
7

Itu belum tentu penting; itu tergantung pada ukuran koleksi Anda dan persyaratan kinerja Anda dan apakah kelas Anda akan digunakan di perpustakaan di mana Anda mungkin tidak tahu persyaratan kinerja. Saya sering tahu ukuran koleksi saya tidak terlalu besar dan waktu saya lebih berharga daripada beberapa mikrodetik kinerja yang diperoleh dengan membuat kode hash yang sempurna; jadi (untuk menghilangkan peringatan yang mengganggu oleh kompiler) Saya cukup menggunakan:

   public override int GetHashCode()
   {
      return base.GetHashCode();
   }

(Tentu saja saya bisa menggunakan #pragma untuk mematikan peringatan juga tapi saya lebih suka cara ini.)

Ketika Anda berada dalam posisi yang Anda lakukan memerlukan kinerja dari semua masalah yang disebutkan oleh orang lain di sini berlaku, tentu saja. Paling penting - jika tidak, Anda akan mendapatkan hasil yang salah saat mengambil item dari kumpulan atau kamus hash: kode hash tidak boleh berbeda dengan masa hidup suatu objek (lebih akurat, selama waktu ketika kode hash diperlukan, seperti saat sedang kunci dalam kamus): misalnya, berikut ini salah karena Nilai bersifat publik sehingga dapat diubah secara eksternal ke kelas selama masa pakai instance, jadi Anda tidak boleh menggunakannya sebagai dasar untuk kode hash:


   class A
   {
      public int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
      }
   }    

Di sisi lain, jika Nilai tidak dapat diubah, boleh saja menggunakan:


   class A
   {
      public readonly int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //OK  Value is read-only and can't be changed during the instance's life time
      }
   }
ILoveFortran
sumber
3
Diturunkan. Ini jelas salah. Bahkan Microsoft menyatakan dalam MSDN ( msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx ) bahwa nilai GetHashCode HARUS berubah ketika status objek berubah dengan cara yang dapat memengaruhi nilai pengembalian panggilan to Equals (), dan bahkan dalam contohnya itu juga memperlihatkan implementasi GetHashCode yang sepenuhnya bergantung pada nilai yang dapat diubah secara publik.
Sebastian PR Gingter
Sebastian, saya tidak setuju: Jika Anda menambahkan objek ke koleksi yang menggunakan kode hash itu akan dimasukkan ke dalam bin tergantung pada kode hash. Jika sekarang Anda mengubah kode hash Anda tidak akan menemukan objek lagi di koleksi karena bin yang salah akan dicari. Ini, sebenarnya, sesuatu yang telah terjadi dalam kode kita dan itulah mengapa saya merasa perlu untuk menunjukkannya.
ILoveFortran
2
Sebastian, Selain itu, saya tidak dapat melihat pernyataan di tautan ( msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx ) yang harus diubah oleh GetHashCode (). Sebaliknya - itu TIDAK boleh berubah selama Equals mengembalikan nilai yang sama untuk argumen yang sama: "Metode GetHashCode untuk objek harus secara konsisten mengembalikan kode hash yang sama selama tidak ada modifikasi pada status objek yang menentukan nilai kembali dari metode Persamaan objek. "Pernyataan ini tidak menyiratkan sebaliknya, bahwa itu harus berubah jika nilai kembali untuk Persamaan berubah.
ILoveFortran
2
@ Joao, Anda membingungkan sisi klien / konsumen dari kontrak dengan produsen / pelaksana. Saya berbicara tentang tanggung jawab pelaksana, yang menimpa GetHashCode (). Anda berbicara tentang konsumen, orang yang menggunakan nilai.
ILoveFortran
1
Kesalahpahaman total ... :) Yang benar adalah bahwa kode hash harus berubah ketika keadaan objek berubah kecuali keadaan tidak relevan dengan identitas objek. Selain itu, Anda tidak boleh menggunakan objek MUTABLE sebagai kunci dalam koleksi Anda. Gunakan objek hanya baca untuk tujuan ini. GetHashCode, Equals ... dan beberapa metode lain yang namanya tidak saya ingat saat ini harus TIDAK PERNAH melempar.
darlove
0

Anda harus selalu menjamin bahwa jika dua objek sama, seperti yang didefinisikan oleh Equals (), mereka harus mengembalikan kode hash yang sama. Seperti yang dinyatakan oleh beberapa komentar lainnya, secara teori ini tidak wajib jika objek tidak akan pernah digunakan dalam wadah berbasis hash seperti HashSet atau Kamus. Saya menyarankan Anda untuk selalu mengikuti aturan ini. Alasannya hanya karena terlalu mudah bagi seseorang untuk mengubah koleksi dari satu jenis ke yang lain dengan maksud yang baik untuk benar-benar meningkatkan kinerja atau hanya menyampaikan kode semantik dengan cara yang lebih baik.

Sebagai contoh, misalkan kita menyimpan beberapa objek dalam Daftar. Beberapa saat kemudian seseorang benar-benar menyadari bahwa HashSet adalah alternatif yang jauh lebih baik karena karakteristik pencarian yang lebih baik misalnya. Inilah saatnya kita bisa mendapat masalah. Daftar akan secara internal menggunakan pembanding kesetaraan default untuk jenis yang berarti Setara dalam kasus Anda sementara HashSet memanfaatkan GetHashCode (). Jika keduanya berperilaku berbeda, demikian juga program Anda. Dan ingatlah bahwa masalah seperti itu bukan yang paling mudah untuk dipecahkan.

Saya telah merangkum perilaku ini dengan beberapa perangkap GetHashCode () lainnya di a posting blog di mana Anda dapat menemukan contoh dan penjelasan lebih lanjut.

Vasil Kosturski
sumber
0

Pada .NET 4.7metode pengesampingan yang disukai GetHashCode()ditunjukkan di bawah ini. Jika menargetkan versi .NET yang lebih lama, sertakan paket nuget System.ValueTuple .

// C# 7.0+
public override int GetHashCode() => (FooId, FooName).GetHashCode();

Dalam hal kinerja, metode ini akan mengungguli sebagian besar implementasi kode hash komposit . The ValueTuple adalah structsehingga tidak akan ada sampah, dan algoritma yang mendasari adalah sebagai cepat karena mendapat.

l33t
sumber
-1

Ini pemahaman saya bahwa GetHashCode () asli mengembalikan alamat memori objek, jadi penting untuk menimpanya jika Anda ingin membandingkan dua objek yang berbeda.

Diedit: Itu tidak benar, metode GetHashCode () asli tidak dapat menjamin kesetaraan 2 nilai. Meskipun objek yang sama mengembalikan kode hash yang sama.

pengguna2855602
sumber
-6

Menurut saya, refleksi di bawah ini menggunakan opsi yang lebih baik mengingat properti publik karena dengan ini Anda tidak perlu khawatir tentang penambahan / penghapusan properti (meskipun tidak begitu skenario umum). Ini saya temukan berkinerja lebih baik juga. (Dibandingkan waktu menggunakan Diagonistics stop watch).

    public int getHashCode()
    {
        PropertyInfo[] theProperties = this.GetType().GetProperties();
        int hash = 31;
        foreach (PropertyInfo info in theProperties)
        {
            if (info != null)
            {
                var value = info.GetValue(this,null);
                if(value != null)
                unchecked
                {
                    hash = 29 * hash ^ value.GetHashCode();
                }
            }
        }
        return hash;  
    }
Guanxi
sumber
12
Implementasi GetHashCode () diharapkan sangat ringan. Saya tidak yakin menggunakan refleksi terlihat dengan StopWatch pada ribuan panggilan, tetapi pasti ada jutaan (bayangkan mengisi kamus dari daftar).
bohdan_trotsenko