it-swarm-tr.com

Referans Türünün İki Örneğini Karşılaştırmak İçin "En İyi Uygulama" Nedir?

Son zamanlarda bunu gördüm, şimdiye kadar iki referans türünün gerçekten aynı olup olmadığını görmek için eşitlik operatörünü ( == ) ve/veya Eşittir yöntemini geçersiz kıldım. data (yani aynı görünen iki farklı durum).

Bunu otomatik olarak test etmeye başladığımdan beri daha fazla kullanıyorum (referans/beklenen verileri iade edilenlerle karşılaştırarak).

MSDN’de kodlama standartları yönergelerinin bazılarına bakarken ben bir _ ile karşılaştım makale buna karşı tavsiyelerde bulundu. Şimdi anlıyorum ki neden makale bunu söylüyor (çünkü onlar aynı örnek) ancak soruyu yanıtlamıyor:

  1. İki referans türünü karşılaştırmanın en iyi yolu nedir?
  2. Uygulamalı mıyız IComparable ? (Bunun sadece değer türleri için ayrılması gerektiğini de belirtmiştim).
  3. Bilmediğim bir arayüz var mı?
  4. Sadece kendimiz mi yiyelim ?!

Çok teşekkürler ^ _ ^

Güncelleştirme

Belgelerden bazılarını yanlış okudum (uzun bir gündü) ve geçersiz kılan Eşittir devam etmenin yolu olabilir).

Referans türlerini uyguluyorsanız, eğer türünüz bir Nokta, String, BigNumber ve benzeri gibi bir baz türüne benziyorsa, Equals yöntemini bir referans türü üzerinde geçersiz kılmayı düşünmelisiniz. Çoğu referans tipi eşitlik operatörünü, hatta aşırı yüklerse, Eşit değerini geçersiz kılmamalıdır. Ancak, karmaşık sayı tipi gibi değer anlamsallığına sahip olması amaçlanan bir referans türü uyguluyorsanız, eşitlik operatörünü geçersiz kılmalısınız.

44
Rob Cooper

Sınıfınızın uygulanması gereken Eşittir adında bir yöntemi olan C # kodunu kodlamış gibi görünüyorsunuz, iki nesneyi "bu iki işaretçilerden (çünkü nesne tutamaçları tam olarak işaretçilerden ibarettir)" den başka bir ölçü kullanarak Aynı hafıza adresi? ".

here 'dan bazı örnek kodlar aldım.

class TwoDPoint : System.Object
{
    public readonly int x, y;

    public TwoDPoint(int x, int y)  //constructor
    {
        this.x = x;
        this.y = y;
    }

    public override bool Equals(System.Object obj)
    {
        // If parameter is null return false.
        if (obj == null)
        {
            return false;
        }

        // If parameter cannot be cast to Point return false.
        TwoDPoint p = obj as TwoDPoint;
        if ((System.Object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public bool Equals(TwoDPoint p)
    {
        // If parameter is null return false:
        if ((object)p == null)
        {
            return false;
        }

        // Return true if the fields match:
        return (x == p.x) && (y == p.y);
    }

    public override int GetHashCode()
    {
        return x ^ y;
    }
}

Java'nın çok benzer mekanizmaları var. equals () method, Object sınıfının bir parçasıdır ve bu tür bir işlevsellik istiyorsanız, sınıfınız onu aşırı yükler.

'==' aşırı yüklenmesinin nedeni, nesneler için kötü bir fikir olabilir, genellikle hala "bunlar aynı işaretçilerdir" karşılaştırmalarını yapabilmek isteyebilirsiniz. Bunlar genellikle, örneğin, yinelenenlerin izin verilmediği bir listeye bir öğe eklemek için kullanılır ve bu operatör standart dışı bir şekilde aşırı yüklenirse, çerçeve işlerinizden bazıları çalışmayabilir.

21
Matt J

.NET'te eşitliği doğru, verimli bir şekilde uygulamak ve kod çoğaltması olmadan zordur. Özellikle, değer anlambilimine sahip referans türleri için (yani eşitliği eşitlik olarak değerlendiren değişmez türler ), System.IEquatable<T> arabirimini uygulamalısınız ve tüm farklı işlemleri uygulamalısınız (Equals, GetHashCode ve ==, !=) ).

Örnek olarak, işte değer eşitliği uygulayan bir sınıf:

class Point : IEquatable<Point> {
    public int X { get; }
    public int Y { get; }

    public Point(int x = 0, int y = 0) { X = x; Y = y; }

    public bool Equals(Point other) {
        if (other is null) return false;
        return X.Equals(other.X) && Y.Equals(other.Y);
    }

    public override bool Equals(object obj) => Equals(obj as Point);

    public static bool operator ==(Point lhs, Point rhs) => object.Equals(lhs, rhs);

    public static bool operator !=(Point lhs, Point rhs) => ! (lhs == rhs);

    public override int GetHashCode() =>X.GetHashCode() ^ Y.GetHashCode();
}

Yukarıdaki koddaki hareketli parçalar sadece koyu renkli bölümlerdir: Equals(Point other) içindeki ikinci satır ve GetHashCode() yöntemi. Diğer kod değişmeden kalmalıdır.

Değişmez değerleri temsil etmeyen referans sınıfları için == ve != operatörlerini uygulamayın. Bunun yerine, nesne kimliğini karşılaştırmak için varsayılan anlamlarını kullanın.

Bilerek kodu, türetilmiş bir sınıf türündeki nesneleri bile eşitler. Çoğu zaman, bu arzu edilmeyebilir, çünkü temel sınıf ile türetilmiş sınıflar arasındaki eşitlik iyi tanımlanmamıştır. Ne yazık ki, .NET ve kodlama kuralları burada çok net değil. Resharper'ın yarattığı kod, başka bir cevapta , bu gibi durumlarda istenmeyen davranışlara karşı hassastır çünkü Equals(object x) ve Equals(SecurableResourcePermission x) _ will bu davaya farklı davranır.

Bu davranışı değiştirmek için, yukarıdaki kesinlikle yazılmış Equals yöntemine ek bir tür denetim eklenmesi gerekir:

public bool Equals(Point other) {
    if (other is null) return false;
    if (other.GetType() != GetType()) return false;
    return X.Equals(other.X) && Y.Equals(other.Y);
}
26
Konrad Rudolph

Aşağıda IEquatable'ı uygularken yapmanız gerekenleri özetledim ve çeşitli MSDN dokümantasyon sayfalarından gerekçeleri sağladım.


özet

  • Değer eşitliği testi istendiğinde (örneğin koleksiyonlardaki nesneleri kullanırken) IEquatable arabirimini uygulamalısınız, sınıfınız için Object.Equals ve GetHashCode işlevlerini geçersiz kılmalısınız.
  • Referans eşitliği için test istendiğinde operatör ==, operatör! = Ve Object.ReferenceEquals komutunu kullanmalısınız.
  • Operatör == ve operatör! =/ ValueTypes ve değişmez referans türleri için geçersiz kılmalısınız.

Gerekçe

IEquatable

System.IEquatable arabirimi, bir nesnenin iki örneğini eşitlik için karşılaştırmak için kullanılır. Nesneler, sınıfta uygulanan mantığa göre karşılaştırılır. Karşılaştırma, nesnelerin farklı olup olmadığını gösteren bir boole değeriyle sonuçlanır. Bu, nesne değerlerinin nasıl farklı olduğunu gösteren bir tamsayı döndüren System.IComparable arabiriminin aksinedir.

IEquatable arabirimi, geçersiz kılınması gereken iki yöntemi bildirir. Eşit yöntemi, gerçek karşılaştırmayı gerçekleştirmek ve nesne değerleri eşitse doğru, doğru değilse yanlış dönmek için uygulamayı içerir. GetHashCode yöntemi, farklı değerler içeren özdeş nesneleri benzersiz şekilde tanımlamak için kullanılabilecek benzersiz bir karma değeri döndürmelidir. Kullanılan karma algoritma tipi uygulamaya özeldir. 

IEquatable.Equals Yöntemi

  • Nesneleriniz için bir dizi veya genel koleksiyonda saklanma olasılığını ele almaları için IEquatable uygulamalısınız.
  • IEquatable'ı uygularsanız, Object.Equals (Object) ve GetHashCode'nin temel sınıf uygulamalarını da geçersiz kılmalısınız, böylece davranışları IEquatable.Equals yöntemininkiyle tutarlı olur

Eşittir () ve Operatör == (C # Programlama Kılavuzu)

  • x.Equals (x), true değerini döndürür.
  • x.Equals (y), y.Equals (x) ile aynı değeri döndürür.
  • (x.Equals (y) && y.Equals (z)) doğru olursa, x.Equals (z) doğru olarak döner.
  • X'in art arda yapılan çağrıları. Eşittir (y), x ve y tarafından başvurulan nesneler değiştirilmediği sürece aynı değeri döndürür.
  • x. Eşit (boş), false değerini döndürür (yalnızca geçersiz değer türleri için. Daha fazla bilgi için, bkz. Boş Tipler (C # Programlama Kılavuzu) .) 
  • Yeni Eşitlik uygulaması istisnalar atmamalıdır.
  • Eşitleri geçersiz kılan herhangi bir sınıfın, Object.GetHashCode öğesini de geçersiz kılması önerilir.
  • Eşitliği (nesneyi) uygulamanın yanı sıra, herhangi bir sınıfın performansı artırmak için kendi türünde Eşitleri (tür) kullanması önerilir.

Varsayılan olarak, operatör == iki referansın aynı nesneyi gösterip göstermediğini belirleyerek referans eşitliği için test eder. Bu nedenle, referans işlevlerinin bu işlevi elde etmek için operatör == uygulamak zorunda olmaları gerekmez. Bir tür değişmez olduğunda, bu durumda, örnekte yer alan veriler değiştirilemez, aşırı yük operatörü == referans eşitliği yerine değer eşitliğini karşılaştırmak faydalı olabilir, çünkü değişken nesneler olarak, bunlar aynı uzunlukta kabul edilebilir. aynı değere sahip oldukları gibi. Operatör == 'in değişmez türlerde geçersiz kılınması iyi bir fikir değildir.

  • Aşırı yüklenmiş operatör == uygulamaları istisnalar atmamalıdır.
  • Operatörü aşırı yükleyen her tür == ayrıca operatörü aşırı yüklemelidir! =.

== Operatör (C # Referans)

  • Önceden tanımlanmış değer türleri için, eşitlik operatörü (==), işlenenlerinin değerleri eşitse true, aksi takdirde false döndürür.
  • Dize dışındaki referans türleri için, iki işleneni aynı nesneye başvurursa, == true değerini döndürür. 
  • Dize türü için, == dizelerin değerlerini karşılaştırır.
  • == işleciniz içindeki == karşılaştırmaları kullanarak boş değeri test ederken, temel nesne sınıfı işlecini kullandığınızdan emin olun. Bunu yapmazsanız, yığın akışıyla sonuçlanan sonsuz tekrarlama gerçekleşir.

Object.Equals Yöntemi (Nesne)

Programlama diliniz operatör aşırı yüklemesini destekliyorsa ve belirli bir tür için eşitlik operatörünü aşırı yüklemeyi seçtiyseniz, bu tür Equals yöntemini geçersiz kılmalıdır. Eşitler yönteminin bu tür uygulamaları, eşitlik işleci ile aynı sonuçları vermelidir.

Aşağıdaki kurallar, a değer türünü uygulamak içindir:

  • ValueType'a Varsayılan Eşitlik uygulaması ile sağlanan performansın üzerinde bir performans elde etmek için Eşitleri geçersiz kılmayı düşünün.
  • Equals seçeneğini geçersiz kılarsanız ve dil operatör aşırı yüklemesini destekliyorsa, eşitlik operatörünü değer türünüz için aşırı yüklemelisiniz.

Aşağıdaki yönergeler a referans tipini uygulamak içindir:

  • Türün semantiği, türün bazı değerleri temsil ettiği gerçeğine dayanıyorsa, referans tipine eşitleme'yi dikkate alın.
  • Çoğu referans tipi, Equals'ı geçersiz kılsalar bile eşitlik operatörünü aşırı yüklememelidir. Bununla birlikte, karmaşık bir sayı türü gibi değer anlambilimine sahip olması amaçlanan bir başvuru türü uyguluyorsanız, eşitlik operatörünü geçersiz kılmanız gerekir.

Ek Gotchas

  • GetHashCode () işlevini geçersiz kılarken, bunları karma kodunda kullanmadan önce NULL için referans türlerini test ettiğinizden emin olun.
  • Burada açıklanan arayüz tabanlı programlama ve operatör aşırı yüklemesi ile ilgili bir sorunla karşılaştım: C # 'de Arayüz Tabanlı Programlama ile Operatör Aşırı Yüklemesi
16
Zach Burlingame

Bu makale sadece eşitlik operatörünü (referans türleri için) geçersiz kılmalarını değil, Eşitleri geçersiz kılmalarını önermektedir. Eşitlik kontrolleri referans kontrollerinden daha fazla bir şey ifade ediyorsa, nesnenizdeki Eşitleri (referans veya değer) geçersiz kılmalısınız. Bir arayüz istiyorsanız, IEquatable (genel koleksiyonlar tarafından kullanılan) da uygulayabilirsiniz. Ancak, IEquatable'ı uygularsanız, IEquatable açıklamalar bölümünün belirttiği gibi, eşitleri de geçersiz kılmalısınız.

IEquatable <T> uygularsanız, Object.Equals (Object) ve GetHashCode'nin temel sınıf uygulamalarını da geçersiz kılmalısınız, böylece davranışları IEquatable <T> .Equals yöntemiyle tutarlı olur. Object.Equals (Object) öğesini geçersiz kılarsanız, geçersiz kılınan uygulamanız, sınıfınızdaki statik Equals (System.Object, System.Object) yöntemine yapılan çağrılar olarak da adlandırılır. Bu, Equals yönteminin tüm çağrılarının tutarlı sonuçlar vermesini sağlar. 

Eşitleri ve/veya eşitlik işlecini uygulayıp uygulamamanız konusunda:

From Eşit Yönteminin Uygulanması

Çoğu referans tipi, Equals'ı geçersiz kılsalar bile eşitlik operatörünü aşırı yüklememelidir.

Kimden Eşitlik ve Eşitlik İşletmecisi İçin Uygulama Esasları (==)

Eşitlik işlecini (==) ne zaman uygularsanız eşitleyin ve aynı şeyi yapmalarını sağlayın.

Bu sadece, eşitlik operatörünü ne zaman uygularsanız Eşitleri geçersiz kılmanız gerektiğini söyler. Bunu yapar not Eşitleri geçersiz kıldığınızda eşitlik operatörünü geçersiz kılmanız gerektiğini söyler.

3
bdukes

Özel karşılaştırmalar sağlayacak karmaşık nesneler için, daha sonra IComparable'ı uygulamak ve Karşılaştırma yöntemlerinde karşılaştırmayı tanımlamak iyi bir uygulamadır.

Örneğin, tek farkın kayıt numarası olabileceği "Araç" nesnelerimiz var ve bunu test etmek için beklenen değerin istediğimiz olmasını sağlamak için karşılaştırmak için kullanıyoruz.

2
Paul Shannon

Resharper'ın otomatik olarak yaptığı şeyi kullanma eğilimindeyim. örneğin, referans türlerimden biri için bunu otomatik olarak yarattı:

public override bool Equals(object obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    return obj.GetType() == typeof(SecurableResourcePermission) && Equals((SecurableResourcePermission)obj);
}

public bool Equals(SecurableResourcePermission obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    return obj.ResourceUid == ResourceUid && Equals(obj.ActionCode, ActionCode) && Equals(obj.AllowDeny, AllowDeny);
}

public override int GetHashCode()
{
    unchecked
    {
        int result = (int)ResourceUid;
        result = (result * 397) ^ (ActionCode != null ? ActionCode.GetHashCode() : 0);
        result = (result * 397) ^ AllowDeny.GetHashCode();
        return result;
    }
}

== işlevini geçersiz kılmak istiyorsanız ve hala ref kontrolleri yapmak istiyorsanız, hala Object.ReferenceEquals adresini kullanabilirsiniz.

1
mattlant

Microsoft, ayarlarının değişmiş gibi görünüyor veya en azından eşitlik operatörünü aşırı yüklememekle ilgili çelişkili bilgiler var. Buna göre Microsoft makale başlıklı Nasıl Yapılır: Bir Tür için Değer Eşitliği Tanımlama:

"== ve! = Operatörleri, sınıf aşırı yüklemese bile sınıflarla kullanılabilir. Ancak, varsayılan davranış, bir referans eşitliği kontrolü yapmaktır. Bir sınıfta, Equals yöntemini aşırı yüklerseniz, aşırı yüklemelisiniz. == ve! = operatörleri, ancak gerekli değildir. "

Eric Lippert'e göre cevabı sorduğum bir soruya göre C # - 'da eşitlik için minimum kod diyor:

“Burada karşılaştığınız tehlike, varsayılan olarak eşitliğe referans veren sizin için tanımlanmış bir == işlecine sahip olmanızdır. Aşırı yüklenmiş bir Eşitler yönteminin eşitlik değerine sahip olduğu ve == referans eşitliğine sahip bir durumda kolayca sona erebilir ve sonra yanlışlıkla referans değerine eşit olmayan değerlerde referans eşitliğini kullanırsınız, bu insan kodu incelemesi tarafından tespit edilmesi zor olan hataya açık bir uygulamadır.

Birkaç yıl önce, bu durumu istatistiksel olarak saptamak için statik bir analiz algoritması üzerinde çalıştım ve çalıştığımız tüm kod tabanlarında milyon satırlık kod başına yaklaşık iki örnek kusur oranı bulduk. Bir yerde geçersiz kılınmış sadece kod tabanları göz önüne alındığında, Eşit, kusur oranı açıkça oldukça yüksek!

Ayrıca, maliyetleri ve riskleri dikkate alın. Eğer zaten IComparable'ın uygulamalarına sahipseniz, tüm operatörleri yazmak, hataları olmayacak ve asla değiştirilmeyecek önemsiz tek gömleklerdir. Yazacağın en ucuz kod. Referans eşitliği değer eşitliği yerine kullanıldığında, görülmesi zor bir hatayı bulmanın ve sabitlemenin sınırsız maliyetine karşılık, bir düzine küçük yöntemle sabit yazma ve test etme maliyeti arasında bir seçim yapıldığında hangisini seçeceğimi biliyorum. "

.NET Framework, yazdığınız herhangi bir türle hiçbir zaman == veya! = Kullanmaz. Fakat tehlike, başkası yaparsa ne olacağını. Bu yüzden, eğer sınıf bir 3. parti içinse, ben her zaman == ve! = Operatörlerini sağlardım. Sınıf sadece grup tarafından dahili olarak kullanılacaksa, muhtemelen == ve! = Operatörlerini de uygularım.

IComparable uygulanmışsa, yalnızca <, <=,> ve> = operatörlerini uygulardım. IComparable, yalnızca türün SortedSet gibi sıralı bir genel kapsayıcıda sıralanırken veya kullanıldığında olduğu gibi, sıralamayı desteklemesi gerektiğinde uygulanmalıdır.

Eğer grup veya şirket, == ve! = Operatörlerini asla uygulamamak için bir politika uygularsa - o zaman elbette bu politikayı izlerdim. Eğer böyle bir politika mevcut olsaydı, referans türüyle kullanıldığında == ve! = Operatörlerinin herhangi bir şekilde görünmesini işaretleyen bir Q/A kod analiz aracıyla zorlamak akıllıca olacaktır.

1
Bob Bryan

Bunun doğru olmasının ne kadar zor olduğu dikkat çekici ...

Microsoft'tan Eşittir ve == bu konuda farklı şeyler yapma önerisi benim için anlamlı değil. Bir noktada, birisi (haklı olarak) Eşittir ve aynı sonucu elde etmek için == bekleyecek ve kod bombalayacak.

Aşağıdakileri yapacak bir çözüm arıyordum:

  • her durumda Eşit veya == kullanılmışsa aynı sonucu elde edin
  • her durumda tamamen polimorfik (temel referanslardan türetilmiş eşitlik çağrısı) olması

Kullandığım şey bu:

  class MyClass : IEquatable<MyClass> {
    public int X { get; }
    public int Y { get; }
    public MyClass(int X, int Y) { this.X = X; this.Y = Y; }

    public override bool Equals(object obj) => obj is MyClass o && X == o.X && Y == o.Y;
    public bool Equals(MyClass o) => object.Equals(this, o);
    public static bool operator ==(MyClass o1, MyClass o2) => object.Equals(o1, o2);
    public static bool operator !=(MyClass o1, MyClass o2) => !object.Equals(o1, o2);

    public override int GetHashCode() => HashCode.Combine(X, Y);
  }

Burada her şey Equals(object) ile sona erer ve bu her zaman polimorfiktir, böylece her iki hedefe de ulaşılır.

Böyle türetmek:

  class MyDerived : MyClass, IEquatable<MyDerived> {
    public int Z { get; }
    public int K { get; }
    public MyDerived(int X, int Y, int Z, int K) : base(X, Y) { this.Z = Z; this.K = K; }

    public override bool Equals(object obj) => obj is MyDerived o && base.Equals(obj) && Z == o.Z && K == o.K;
    public bool Equals(MyDerived o) => object.Equals(this, o);
    public static bool operator ==(MyDerived o1, MyDerived o2) => object.Equals(o1, o2);
    public static bool operator !=(MyDerived o1, MyDerived o2) => !object.Equals(o1, o2);

    public override int GetHashCode() => HashCode.Combine(base.GetHashCode(), Z, K);
  }

Temelde bir tane getcha hariç aynı olan - Equals(object)base.Equals işlevini çağırmak istediğinde base.Equals(object) işlevini çağırmaya dikkat edin ve base.Equals(MyClass) işlevini aramayın (ki bu sonsuz bir özyinelemeye neden olur).

Buradaki bir uyarı, bu uygulamada Equals(MyClass)'ın bir miktar boks yapacağı, ancak boks/unboxing'in oldukça optimize edilmiş olduğu ve bu benim için yukarıdaki hedeflere ulaşmaya değer olduğu yönünde.

demo: https://dotnetfiddle.net/lrMWV8

(C #> 7.0 için olduğunu unutmayın)
(Konrad'ın cevabına dayanarak)

0
kofifus

Eşitlik için nesneleri kontrol etmek kadar basit bir şey almanın .NET'in tasarımında biraz zor olduğuna inanıyorum.

Yapı için

1) IEquatable<T> öğesini uygulayın. Performansı gözle görülür biçimde iyileştirir.

2) Şimdi kendi Equals değerine sahip olduğunuza göre, GetHashCode değerini geçersiz kılın ve object.Equals işlevini de geçersiz kılan çeşitli eşitlik kontrolleriyle tutarlı olun.

3) Aşırı yükleme == ve != operatörlerinin, eğer bir yapıyı bir == veya != ile bir yapıyla istemeden eşitlemeniz durumunda derleyici uyarır, ancak Equals yöntemleriyle tutarlı olması iyi olur, çünkü derleyicilerin uyarılması gerekir.

public struct Entity : IEquatable<Entity>
{
    public bool Equals(Entity other)
    {
        throw new NotImplementedException("Your equality check here...");
    }

    public override bool Equals(object obj)
    {
        if (obj == null || !(obj is Entity))
            return false;

        return Equals((Entity)obj);
    }

    public static bool operator ==(Entity e1, Entity e2)
    {
        return e1.Equals(e2);
    }

    public static bool operator !=(Entity e1, Entity e2)
    {
        return !(e1 == e2);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
    }
}

Sınıf için

MS’ten:

Çoğu referans tipi, Equals'ı geçersiz kılsalar bile eşitlik operatörünü aşırı yüklememelidir.

Bana göre ==, daha fazla Equals yöntemi için sözdizimsel bir şeker gibi, değer eşitliği gibi hisseder. a == b yazmak, a.Equals(b) yazmaktan çok daha sezgiseldir. Nadiren referans eşitliğini kontrol etmemiz gerekir. Fiziksel nesnelerin mantıksal temsilleriyle uğraşan soyut seviyelerde bu, kontrol etmemiz gereken bir şey değildir. == ve Equals için farklı bir anlambilimine sahip olmak gerçekten kafa karıştırıcı olabilir. Öncelikle değer eşitliği için == ve başvuru için Equals (veya IsSameAs gibi daha iyi bir ad) olması gerektiğine inanıyorum. Burada MS rehberini ciddiye almayı çok isterim, sadece benim için doğal olmadığı için değil, aynı zamanda == 'nin aşırı yüklenmesi de önemli bir zarar vermez. Bu, ısırılabilecek genel olmayan Equals veya GetHashCode 'i geçersiz kılmadığından farklıdır, çünkü çerçeve == hiçbir yerde değil, yalnızca biz kullanırsak. 'den kazandığım tek gerçek fayda, aşırı yüklenmemesi == ve !=' nin üzerinde kontrolüm olmadığı bütün çerçevenin tasarımına uygunluk olacaktır. Ve bu gerçekten büyük bir şey, ne yazık ki ona sadık kalacağım.

Referans anlambilimiyle (değişken nesneler)

1) Equals ve GetHashCode öğelerini geçersiz kıl.

2) IEquatable<T> 'u uygulamak zorunlu değil, eğer varsa bir güzel olacak.

public class Entity : IEquatable<Entity>
{
    public bool Equals(Entity other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        //if your below implementation will involve objects of derived classes, then do a 
        //GetType == other.GetType comparison
        throw new NotImplementedException("Your equality check here...");
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Entity);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
    }
}

Değer anlambilimiyle (değişmez nesneler)

Bu zor kısmı. Dikkatli olunmazsa kolayca karışabilir ..

1) Equals ve GetHashCode öğelerini geçersiz kıl.

2) Equals ile eşleşmesi için == ve != dosyalarını aşırı yükleyin. Boşlar için çalıştığından emin olun .

2) IEquatable<T> 'u uygulamak zorunlu değil, eğer varsa bir güzel olacak.

public class Entity : IEquatable<Entity>
{
    public bool Equals(Entity other)
    {
        if (ReferenceEquals(this, other))
            return true;

        if (ReferenceEquals(null, other))
            return false;

        //if your below implementation will involve objects of derived classes, then do a 
        //GetType == other.GetType comparison
        throw new NotImplementedException("Your equality check here...");
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Entity);
    }

    public static bool operator ==(Entity e1, Entity e2)
    {
        if (ReferenceEquals(e1, null))
            return ReferenceEquals(e2, null);

        return e1.Equals(e2);
    }

    public static bool operator !=(Entity e1, Entity e2)
    {
        return !(e1 == e2);
    }

    public override int GetHashCode()
    {
        throw new NotImplementedException("Your lightweight hashing algorithm, consistent with Equals method, here...");
    }
}

Sınıfınız devralınabiliyorsa nasıl ücretlendirileceğine dikkat edin, bu gibi durumlarda, bir temel sınıf nesnesinin türetilmiş bir sınıf nesnesine eşit olup olmadığını belirlemeniz gerekir. İdeal olarak, türetilmiş bir sınıf nesnesinin olmaması durumunda eşitlik kontrolü için kullanıldığında, bir temel sınıf örneği türetilmiş bir sınıf örneğine eşit olabilir ve bu gibi durumlarda, temel sınıfın genel Type'sinde Equals eşitliği kontrol edilmesine gerek yoktur.

Genel olarak kodu kopyalamamaya dikkat edin. Yeniden kullanımı kolaylaştıracak bir şablon olarak genel bir soyut temel sınıfı (IEqualizable<T> ya da öylesine) yapabilirdim, ama ne yazık ki C # da beni ek sınıflardan türetmekten alıkoydu.

0
nawfal