Eşittir yöntemi geçersiz kılındığında GetHashCode'u geçersiz kılmak neden önemlidir?


1444

Aşağıdaki sınıf verildi

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

EqualsÇünkü s tablo Fooiçin bir satır temsil yöntemi geçersiz kılınmıştır Foo. Geçersiz kılmak için tercih edilen yöntem GetHashCodehangisidir?

Geçersiz kılmak neden önemlidir GetHashCode?


36
Çarpışmalar nedeniyle, özellikle sözlükleri kullanırken hem eşittir hem de gethashcode uygulamak önemlidir. iki nesne aynı karma kodu döndürürse, zincirleme ile sözlüğe eklenir. Maddeye erişirken eşittir yöntemi kullanılır.
DarthVader

Yanıtlar:


1319

Evet, öğenizin bir sözlükte bir anahtar olarak mı yoksa HashSet<T>vb. Kullanılıp kullanılmayacağı önemlidir - çünkü bu (özel bir yokluğunda IEqualityComparer<T>) öğeleri gruplara ayırmak için kullanılır. İki öğenin karma kodu eşleşmezse, bunlar asla eşit kabul edilemez ( Eşittirler asla çağrılmaz).

GetHashCode () metodu yansıtmalıdır Equalsmantık; kurallar:

  • iki şey (eşitse Equals(...) == true) o zaman gerekir için aynı değeri döndürürGetHashCode()
  • Eğer GetHashCode()eşit, bunun değil onları aynı olması için gerekli olan; bu bir çarpışmadır ve Equalsgerçek bir eşitlik olup olmadığını görmek için çağrılır.

Bu durumda, " return FooId;" uygun bir GetHashCode()uygulama gibi görünüyor . Birden fazla özelliği test ediyorsanız, çapraz çarpışmaları azaltmak için bunları (örneğin new Foo(3,5), farklı bir karma kodu vardır new Foo(5,3)) aşağıdaki gibi kod kullanarak birleştirmek yaygındır :

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 - kolaylık için, ayrıca sağlayarak düşünebilirsiniz ==ve !=operatörler geçersiz kılmak için Equalsve GetHashCode.


Bunu yanlış anladığınızda ne olduğuna dair bir gösteri burada .


49
Ahy böyle faktörlerle çarpıldığını sorabilir miyim?
Leandro López

22
Aslında bunlardan birini kaybedebilirdim; mesele, çarpışma sayısını en aza indirmeye çalışmaktır - böylece {1,0,0} nesnesinin {0,1,0} ve {0,0,1} değerinden farklı bir karması olur (ne demek istediğimi görürseniz) ),
Marc Gravell

13
Daha net hale getirmek için sayıları değiştirdim (ve bir tohum ekledim). Bazı kodlar farklı sayılar kullanır - örneğin C # derleyicisi (anonim türler için) 0x51ed270b tohumunu ve -1521134295 faktörünü kullanır.
Marc Gravell

76
@Leandro López: Genellikle faktörler asal sayılar olarak seçilir çünkü çarpışma sayısını azaltır.
Andrei Rînea

29
"Oh - kolaylık olması açısından, Equals ve GethashCode'u geçersiz kılarken == ve! = Operatörleri sağlamayı da düşünebilirsiniz.": Microsoft, değiştirilemeyen nesneler için operatör == uygulamasını engeller - msdn.microsoft.com/en-us/library/ ms173147.aspx - "Değişmez tiplerde operatörü == geçersiz kılmak iyi bir fikir değil."
antiduh

137

GetHashCode()Doğru bir şekilde uygulanması çok zordur, çünkü Marc'ın daha önce bahsettiği kurallara ek olarak, karma kodu bir nesnenin ömrü boyunca değişmemelidir. Bu nedenle, karma kodunu hesaplamak için kullanılan alanların değiştirilemez olması gerekir.

Nihayet NHibernate ile çalışırken bu soruna bir çözüm buldum. Benim yaklaşım nesnenin kimliğinden karma kodu hesaplamaktır. Kimlik yalnızca kurucudan ayarlanabilir, bu nedenle çok düşük bir olasılıkla kimliğini değiştirmek isterseniz, yeni bir kimliği ve dolayısıyla yeni bir karma kodu olan yeni bir nesne oluşturmanız gerekir. Bu yaklaşım GUID'lerle en iyi şekilde çalışır, çünkü rastgele bir kimlik oluşturan parametresiz bir kurucu sağlayabilirsiniz.


20
@vanja. Ben bununla ilgili olduğuna inanıyorum: Eğer bir sözlüğe nesne eklemek ve daha sonra nesnenin kimliğini değiştirmek, daha sonra getirirken sözlükten asla elde etmek için onu almak için farklı bir karma kullanacak.
ANeves

74
Microsoft'un GetHashCode () işleviyle ilgili belgeleri, nesne karmasının kullanım ömrü boyunca tutarlı kalması gerektiğini belirtir veya ima etmez. Aslında, özellikle izin verilemeyen izin verilen bir durumu açıklar : "Bir nesnenin GetHashCode yöntemi, nesnenin Eşittir yönteminin dönüş değerini belirleyen nesne durumunda herhangi bir değişiklik olmadığı sürece tutarlı olarak aynı karma kodunu döndürmelidir. ."
PeterAllenWebb

37
"karma kodu bir nesnenin ömrü boyunca değişmemelidir" - bu doğru değildir.
apocalypse

7
Bunu söylemenin daha iyi bir yolu, "hash kodu (veya eşitliklerin değerlendirilmesi), nesnenin bir koleksiyonun anahtarı olarak kullanıldığı süre boyunca değişmesidir" Bu nedenle, nesneyi anahtar olarak bir sözlüğe eklerseniz, GetHashCode ve Equals siz nesneyi sözlükten kaldırana kadar belirli bir girdi için çıktılarını değiştirmez.
Scott Chamberlain

11
@ScottChamberlain Bence yorumunda DEĞİL unuttum, şöyle olmalıdır: "hash kodu (ne de eşittir değerlendirme) nesne bir koleksiyon için bir anahtar olarak kullanıldığı süre boyunca değişmemelidir". Sağ?
Stan Prokop

57

Eşittirleri geçersiz kılarak temel olarak, belirli bir türün iki örneğini nasıl karşılaştıracağınızı daha iyi bilen kişi olduğunuzu belirlersiniz, bu nedenle en iyi karma kodunu sağlamak için en iyi aday olmanız muhtemeldir.

Bu, ReSharper'ın sizin için GetHashCode () işlevini nasıl yazdığına bir örnektir:

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

Gördüğünüz gibi, sınıftaki tüm alanlara dayalı olarak iyi bir karma kodu tahmin etmeye çalışır, ancak nesnenizin etki alanını veya değer aralıklarını bildiğiniz için daha iyi bir kod sağlayabilirsiniz.


7
Bu her zaman sıfır döndürmez mi? Muhtemelen sonucu 1 olarak başlatmalıdır! Ayrıca birkaç tane daha noktalı virgül gerekir.
Sam Mackrill

16
XOR operatörünün (^) ne yaptığını biliyor musunuz?
Stephen Drew

1
Dediğim gibi, R # sizin için yazıyor (en azından 2008'de geri döndü). Açıkçası, bu pasajın programcı tarafından bir şekilde ayarlanması amaçlanmıştır. Eksik noktalı virgüllere gelince ... evet, kodu Visual Studio'daki bir bölge seçiminden kopyalayıp yapıştırdığımda bunları dışarıda bıraktım. İnsanların her ikisini de çözeceğini düşündüm.
Tuzak

3
@SamMackrill Eksik noktalı virgüllere ekledim.
Matthew Murdoch

5
@SamMackrill Hayır, her zaman 0 döndürmez 0 ^ a = a, bu yüzden 0 ^ m_someVar1 = m_someVar1. O da başlangıç değerini ayarlayabilirsiniz resultiçin m_someVar1.
Millie Smith

41

Lütfen nullgeçersiz kılma sırasında obj parametresini kontrol etmeyi unutmayın Equals(). Ve ayrıca türü karşılaştırın.

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

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

    return fooItem.FooId == this.FooId;
}

Bunun nedeni: Equalsile karşılaştırıldığında yanlış döndürmelidir null. Ayrıca bkz. Http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx


6
Bu tür denetimi, bir alt sınıfın kendi sınıfının bir parçası olarak üst sınıf Eşittir yöntemine başvurduğu durumda başarısız olur (yani base.Equals (obj)) - bunun yerine kullanmalıdır
sweetfa

@sweetfa: Alt sınıfın Eşit yönteminin nasıl uygulandığına bağlıdır. Ayrıca iyi çalışacak olan base.Equals ((BaseType) obj)) öğesini çağırabilir.
huha

2
Hayır, olmaz: msdn.microsoft.com/en-us/library/system.object.gettype.aspx . Ayrıca, bir yöntemin uygulanması, çağrılma şekline bağlı olarak başarısız olmamalı veya başarılı olmamalıdır. Bir nesnenin çalışma zamanı tip sonra bazı BaseClass bir alt sınıf Eşittir ise eğer () BaseClass gerçek dönmelidir objgerçekten eşittir thisçağrıldı nasıl Eşittir () BaseClass hiçbir konuda.
Jüpiter

2
Hareketli fooItemboş olduğunda veya yanlış tip daha iyi performans sergilemekte boş olup olmadığını kontrol sonra üstüne ve.
IllidanS4 Monica'nın

1
@ 40 Alfa, evet, o obj as Foozaman geçersiz olur.
IllidanS4 Monica'nın

35

Nasıl olur:

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

Performansın bir sorun olmadığını varsaymak :)


1
erm - ancak int tabanlı bir yöntem için bir dize döndürüyorsunuz; _0
jim tollan

32
Hayır, String döndüren bir int döndüren GetHashCode () yöntemini çağırır.
Richard Clayton

3
Bunun istediğim kadar hızlı olmasını beklemiyorum, sadece değer türleri için olan boks için değil, aynı zamanda performans için de string.Format. Gördüğüm bir başka inek de new { prop1, prop2, prop3 }.GetHashCode(). Ama hangisi bu ikisi arasında daha yavaş olacağını yorum yapamam. Aletleri kötüye kullanmayın.
nawfal

16
Bu { prop1="_X", prop2="Y", prop3="Z" }ve için doğrudur { prop1="", prop2="X_Y", prop3="Z_" }. Muhtemelen bunu istemiyorsun.
voetsjoeba

2
Evet, alt çizgi sembolünü her zaman çok yaygın olmayan bir şeyle değiştirebilirsiniz (örneğin, •, ▲, ►, ◄, ☺, ☻) ve kullanıcılarınızın bu sembolleri kullanmayacağını umuyoruz ... :)
Ludmil Tinkov

13

Başa çıkmak için iki sorunumuz var.

  1. GetHashCode()Nesnedeki herhangi bir alan değiştirilebilirse, mantıklı bir bilgi sağlayamazsınız . Ayrıca genellikle bağımlı bir koleksiyonda ASLA bir nesne kullanılmayacaktır GetHashCode(). Dolayısıyla, uygulamanın maliyeti GetHashCode()genellikle buna değmez veya mümkün değildir.

  2. Birisi nesnenizi çağıran bir koleksiyona koyarsa GetHashCode()ve doğru bir şekilde davranmadan Equals()da geçersiz kıldığınızda GetHashCode(), o kişi sorunu izlemek için günler geçirebilir.

Bu yüzden varsayılan olarak yaparım.

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

5
GetHashCode'dan istisna atmak, Object sözleşmesinin ihlalidir. Bir GetHashCodeişlevi tanımlamakta zorluk yoktur, böylece eşit olan iki nesne aynı karma kodunu döndürür; return 24601;ve return 8675309;her ikisinin de geçerli uygulamaları olacaktır GetHashCode. Performansı Dictionaryyalnızca öğe sayısı az olduğunda iyi olacaktır ve öğe sayısı arttıkça çok kötü olacaktır, ancak her durumda doğru şekilde çalışacaktır.
supercat

2
@supercat, Nesne içindeki tanımlama alanları değişebiliyorsa GetHashCode'u mantıklı bir şekilde uygulamak mümkün değildir, çünkü karma kodu asla değişmemelidir. Söylediklerinizi yapmak, birinin performans sorununu takip etmek için günlerce zaman harcamasına, daha sonra haftalarca sözlüklerin kullanımını kaldırmak için yeniden tasarlanan büyük bir sisteme yol açabilir.
Ian Ringrose

2
Equals () 'a ihtiyaç duyduğum tanımladığım tüm sınıflar için böyle bir şey yapardım ve bu nesneyi asla bir koleksiyonda anahtar olarak kullanamayacağımdan emindim. Sonra bir gün bir DevExpress XtraGrid denetimine girdi olarak böyle bir nesne kullandım bir program çöktü. Görünüşe göre, XtraGrid, arkamdan, bir HashTable veya nesnelerime dayalı bir şey oluşturuyordu. Bu konuda DevExpress destek insanlarıyla küçük bir tartışmaya girdim. Bileşenlerinin işlevselliğini ve güvenilirliğini, belirsiz bir yöntemin bilinmeyen bir müşteri uygulamasına dayandırmanın akıllıca olmadığını söyledim.
RenniePet

DevExpress insanları oldukça sinsi, temelde GetHashCode () yönteminde bir istisna atmak için aptal olmalıyım diyorlardı. Hala yaptıklarını yapmak için alternatif bir yöntem bulmaları gerektiğini düşünüyorum - Marc Gravell'i GetHashCode'a () bağımlı olmadan keyfi nesnelerin sözlüğünü nasıl oluşturduğunu açıklayan farklı bir iş parçacığını hatırlıyorum - nasıl yaptığını hatırlayamıyorum rağmen.
RenniePet

4
@RenniePet, bir istisna atma nedeniyle ezilme daha iyi olmalı, daha sonra geçersiz bir uygulama nedeniyle hata bulmak çok zor olmalıdır.
Ian Ringrose

12

Bunun nedeni, çerçevenin aynı olan iki nesnenin aynı karma koduna sahip olmasını gerektirmesidir. İki nesnenin özel bir karşılaştırmasını yapmak için eşittir yöntemini geçersiz kılarsanız ve iki nesne yöntemle aynı kabul edilirse, iki nesnenin karma kodunun da aynı olması gerekir. (Sözlükler ve Hashtables bu ilkeye dayanır).


11

Sadece yukarıdaki cevapları eklemek için:

Eşittirleri geçersiz kılmazsanız, varsayılan davranış, nesnelerin başvurularının karşılaştırılmasıdır. Aynı durum karma kod için de geçerlidir - varsayılan uygulama genellikle başvurunun bellek adresini temel alır. Eşittirleri geçersiz kıldığınızdan, doğru davranış, başvurularda değil Eşitlerde uyguladığınız her şeyi karşılaştırmak anlamına gelir, bu nedenle hashcode için aynısını yapmanız gerekir.

Sınıfınızın istemcileri, hashcode'un eşittir yöntemine benzer bir mantığa sahip olmasını bekler, örneğin bir IEqualityComparer kullanan linq yöntemleri önce hashcode'ları karşılaştırır ve yalnızca eşit olduklarında daha pahalı olabilecek Equals () yöntemini karşılaştırırlar hashcode uygulamazsak, eşit nesnenin muhtemelen farklı hashcode'ları olacaktır (çünkü farklı bellek adresleri vardır) ve yanlış olarak eşit olarak belirlenir (Eşittir () bile vurulmaz).

Buna ek olarak, bir sözlükte kullandıysanız nesnenizi bulamayabileceğiniz sorun dışında (bir hashcode tarafından eklendiğinden ve aradığınızda varsayılan hashcode muhtemelen farklı ve yine Eşittir () Marc Gravell'in cevabında açıkladığı gibi, aynı anahtarlara izin vermemesi gereken sözlük veya hashset kavramını da ihlal ediyorsunuz - Eşit değerleri aştığınızda bu nesnelerin temelde aynı olduğunu zaten beyan ettiniz, böylece Her ikisinin de benzersiz bir anahtarı olduğu düşünülen bir veri yapısında farklı anahtarlar olmasını istemezler, ancak farklı bir karma kodları olduğundan "aynı" anahtar farklı anahtar olarak eklenir.


8

Hash kodu, Dictionary, Hashtable, HashSet vb. Gibi karma tabanlı koleksiyonlar için kullanılır. Bu kodun amacı, belirli bir nesneyi belirli bir gruba (kova) koyarak çok hızlı bir şekilde önceden sıralamaktır. Bu ön sıralama, hash-koleksiyonundan geri almanız gerektiğinde bu nesneyi bulmanıza çok yardımcı olur, çünkü kod, nesnenizi tüm nesneler yerine yalnızca bir kovada aramak zorundadır. Karma kodların daha iyi dağılımı (daha iyi benzersizlik) daha hızlı geri alma. Her nesnenin benzersiz bir karma koduna sahip olduğu ideal durumda, onu bulmak O (1) işlemidir. Çoğu durumda O (1) 'e yaklaşır.


7

Mutlaka önemli değildir; koleksiyonlarınızın boyutuna ve performans gereksinimlerinize ve sınıfınızın performans gereksinimlerini bilmediğiniz bir kütüphanede kullanılıp kullanılmayacağına bağlıdır. Koleksiyon boyutlarının çok büyük olmadığını ve zamanımın mükemmel bir karma kodu oluşturarak elde edilen birkaç mikrosaniye performanstan daha değerli olduğunu sık sık biliyorum; yani (derleyici tarafından rahatsız edici uyarı kurtulmak için) Ben sadece kullanın:

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

(Tabii ki uyarıyı da kapatmak için #pragma kullanabilirim ama bu yolu tercih ederim.)

Eğer konumda olduğunda bunu yapmak Burada elbette uygulamak başkaları tarafından bahsedilen sorunların hepsinden daha performansı gerekir. En önemlisi - aksi takdirde, bir karma kümesinden veya sözlükten öğe alırken yanlış sonuçlar alırsınız: karma kodu, nesnenin yaşam süresine göre değişmemelidir (daha doğru, karma kodunun gerektiği zaman, örneğin, sözlükte bir anahtar)): örneğin, Değer herkese açık olduğu için aşağıdakiler yanlıştır ve bu nedenle örneğin yaşam süresi boyunca sınıfa harici olarak değiştirilebilir, bu nedenle hash kodu için temel olarak kullanmamalısınız:


   class A
   {
      public int Value;

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

Öte yandan, Değer değiştirilemezse kullanmakta fayda vardır:


   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
      }
   }

3
Downvoted. Bu çok yanlış. Microsoft bile MSDN'de ( msdn.microsoft.com/en-us/library/system.object.gethashcode.aspx ) nesne durumu çağrının dönüş değerini etkileyebilecek şekilde değiştiğinde GetHashCode değerinin değişmesi GEREKİR 'e eşittir () ve örneklerinde bile halka açık olarak değiştirilebilir değerlere tamamen bağımlı olan GetHashCode uygulamalarını gösterir.
Sebastian PR Gingter

Sebastian, katılmıyorum: Karma kodları kullanan bir koleksiyona nesne eklerseniz, karma koduna bağlı bir kutuya konulur. Şimdi karma kodunu değiştirirseniz, yanlış bölme aranacağından nesneyi koleksiyonda tekrar bulamazsınız. Bu, aslında, kodumuzda olan bir şey ve bu yüzden bunu belirtmek için gerekli buldum.
ILoveFortran

2
Sebastian, Buna ek olarak, bağlantıda ( msdn.microsoft.com/tr-tr/library/system.object.gethashcode.aspx ) GetHashCode () ' un değiştirmesi gereken bir ifade göremiyorum . Aksine - Eşittirler aynı bağımsız değişken için aynı değeri döndürdüğü sürece DEĞİŞTİRİLMEMELİDİR: "Bir nesne için GetHashCode yöntemi, dönüş değerini belirleyen nesne durumunda herhangi bir değişiklik olmadığı sürece tutarlı olarak aynı karma kodunu döndürmelidir "Bu ifade, Eşit değerlerin dönüş değeri değişirse değişmesi gerektiği anlamına gelmez.
ILoveFortran

2
@Joao, yapımcı / uygulayıcı ile sözleşmenin müşteri / tüketici tarafını karıştırıyorsunuz. GetHashCode'u () geçersiz kılan uygulayıcının sorumluluğu hakkında konuşuyorum. Siz tüketiciyi, değeri kullanan kişiyi konuşuyorsunuz.
ILoveFortran

1
Tam yanlış anlama ... :) Gerçek şu ki, durum nesnenin kimliğiyle alakasız olmadığı sürece, nesnenin durumu değiştiğinde karma kodunun değişmesi gerekir. Ayrıca, koleksiyonlarınızda asla MUTABLE nesnesini anahtar olarak kullanmamalısınız. Bu amaçla salt okunur nesneleri kullanın. GetHashCode, Equals ... ve isimlerini şu an hatırlamadığım bazı yöntemler ASLA atmamalı.
darlove

0

İki nesne Eşittir () ile tanımlandığı gibi eşitse, aynı karma kodunu döndürmeleri gerektiğini her zaman garanti etmelisiniz. Diğer yorumların bazılarının belirttiği gibi, teoride, nesne HashSet veya Dictionary gibi karma tabanlı bir kapta asla kullanılmayacaksa, bu zorunlu değildir. Yine de bu kurala uymanızı tavsiye ederim. Bunun nedeni, basitçe performansı gerçekten artırmak veya kod anlambilimini daha iyi bir şekilde iletmek amacıyla bir koleksiyonu bir türden diğerine değiştirmek için çok kolay olmasıdır.

Örneğin, bazı nesneleri Listede tuttuğumuzu varsayalım. Bir süre sonra birisi, örneğin daha iyi arama özellikleri nedeniyle bir HashSet'in çok daha iyi bir alternatif olduğunu fark eder. İşte o zaman başımız belaya girebilir. Liste, HashSet GetHashCode () yöntemini kullanırken durumunuzda Eşittir anlamına gelen tür için varsayılan eşitlik karşılaştırıcısını dahili olarak kullanır. İkisi farklı davranırsa, programınız da farklı davranır. Ayrıca, bu tür sorunların giderilmesinin en kolay yolu olmadığını unutmayın.

Bu davranışı, daha fazla örnek ve açıklama bulabileceğiniz bir blog yayınında diğer bazı GetHashCode () tuzaklarıyla özetledim .


0

İtibariyle .NET 4.7geçersiz kılma için tercih edilen bir yöntem GetHashCode()aşağıda gösterilmiştir. Daha eski .NET sürümlerini hedefliyorsanız, System.ValueTuple nuget paketini ekleyin .

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

Performans açısından, bu yöntem birçok karma karma kod uygulamasından daha iyi performans gösterecektir . ValueTuple bir olduğunu structbu nedenle herhangi bir çöp olmayacak ve altta yatan algoritma kadar hızlı o alır gibi olduğunu.


-1

Anladığım kadarıyla orijinal GetHashCode () nesnenin bellek adresini döndürüyor, bu nedenle iki farklı nesneyi karşılaştırmak istiyorsanız geçersiz kılmak önemlidir.

DÜZENLENMİŞ: Bu yanlıştı, özgün GetHashCode () yöntemi 2 değerin eşitliğini sağlayamaz. Eşit olan nesneler aynı karma kodu döndürür.


-6

Aşağıda yansımayı kullanmak bana kamu mülkleri göz önüne alındığında daha iyi bir seçenek gibi görünüyor, çünkü bununla mülklerin eklenmesi / kaldırılması konusunda endişelenmenize gerek yok (çok yaygın olmasa da). Ben de daha iyi performans buldum. (Diagonistics kronometre kullanarak karşılaştırıldığında zaman).

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

12
GetHashCode () uygulamasının çok hafif olması bekleniyor. Yansıma kullanarak binlerce aramada StopWatch ile fark edilir emin değilim, ama kesinlikle milyonlarca (bir listeden bir sözlük doldurmayı düşünün).
bohdan_trotsenko
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.