2008-09-16 27 views
6

Referans türleri için Equals() uygulaması göründüğünden daha zordur. Benim şu anki kanonik uygulaması şöyledir:Referans türleri için Equals() 'ın "en iyi" kanonik uygulaması nedir?

public bool Equals(MyClass obj) 
{ 
    // If both refer to the same reference they are equal. 
    if(ReferenceEquals(obj, this)) 
    return true; 

    // If the other object is null they are not equal because in C# this cannot be null. 
    if(ReferenceEquals(obj, null)) 
    return false; 

    // Compare data to evaluate equality  
    return _data.Equals(obj._data); 
} 

public override bool Equals(object obj) 
{ 
    // If both refer to the same reference they are equal. 
    if(ReferenceEquals(obj, this)) 
    return true; 

    // If the other object is null or is of a different types the objects are not equal. 
    if(ReferenceEquals(obj, null) || obj.GetType() != GetType()) 
    return false; 

    // Use type-safe equality comparison 
    return Equals((MyClass)obj); 
} 

public override int GetHashCode() 
{ 
    // Use data's hash code as our hashcode 
    return _data.GetHashCode(); 
} 

Ben bu her köşesini (devralma ve gibi) durumlarda kapsar ama yanlış olabileceğini düşünüyorum. Siz ne düşünüyorsunuz?

cevap

4

Bunu bir süre önce oldukça kapsamlı bir kılavuz yazdım. Bir başlangıç ​​için eşit uygulamalarınız paylaşılmalıdır (yani, bir nesneyi alan aşırı yüklenme, güçlü bir şekilde yazılan nesneye sahip olana geçmelidir). Ek olarak, GetHashCode'u geçersiz kılmaya ihtiyaç duyduğunuz için nesnenizin değişmez olması gibi şeyleri göz önünde bulundurmanız gerekir. Burada daha fazla bilgi:

http://gregbeech.com/blog/implementing-object-equality-in-dotnet

+0

Uygulamam "paylaşıldı". Gördüğünüz gibi, Eşittir (Object) sonunda Equals (MyClass) 'a bir çağrı var. Mutability ve GetHashCode() sorunlarının farkındayım; ama bu önemli bir gözlem. Beni birkaç kez ısırdı. Sadece "sınıflar" okuduğunu bildirmenin "kolay" bir yolu olmadığı için çok kötü. –

+0

Bağlantı şimdilik bozuk. – Restuta

0

Mirasla ilgili olarak, OO paradigmasının sihrini yapmasına izin vermelisiniz. Özellikle, GetType() denetiminin kaldırılması gerektiğinden, bu, polimorfizmi çizgiye indirebilir.

+1

Katılmıyorum. Meyve sınıfından türeyen Apple ve Orange sınıflarımız olduğunu hayal edin. Meyvelerdeki Eşitlik uygulamasındaki GetType() işaretini kaldırırsak, her türetilmiş sınıfın Eşittir() öğelerini doğru bir şekilde geçersiz kılmadığı sürece Elmaları Portakalla karşılaştırabiliriz. Çok çabuk dağınık olabilir. –

0

Chakrit ile aynı fikirdeyim, farklı türdeki nesnelerin aynı veriye veya kimliğe sahip olduklarında semantik olarak eşit olmasına izin verilmelidir. aynı zamanda bir başvuru türü ise this._data boş olmadığını

public override bool Equals(object obj) 
    { 
     var other = obj as MyClass; 
     if (other == null) return false; 

     return this.data.Equals(other.data); 
    } 
+0

Sana katılmıyorum. Bu, Elmaları Portakalla karşılaştırmamızı sağlar. –

+0

Önemli olan, belki de onların eşit olmasını istemektir. GetType denetimi örneğin proxy'lerin kullanımına izin vermez; 2 farklı nesneye sahip olacaksınız, biri farklı türde bir kabın içine sarılmış, ancak bunları aynı şekilde tanımlamak istiyorsunuz. –

+0

@SantiagoPalladino: "Object.Equals" den daha gevşek bir denklik tanımı kullanan eşitlik karşılaştırıcılarını tanımlamak genellikle mantıklıdır. Örneğin, .net, dizeler farklı olsa bile, "HELLO" ya "Hello" ya da "heLlO" ya eşdeğer olan çeşitli büyük/küçük harf duyarsız dizge karşılaştırıcılarını tanımlar. Bu tür karşılaştırmalar, farklı türler olarak eşit nesneler olarak kabul edebilir. "Object.Equals" i geçersiz kılan nesnelerin nosyonunu çok farklı bir şekilde tanımlamak için, farklı türdeki nesnelerin eşitsiz bir şekilde karşılaştırma yapmasına izin vermeyecek kadar eşdeğer bir denklik ilişkisi tanımlamak için ... – supercat

1

Daha İyi umut:

Şahsen ben şu kullanın.

public bool Equals(MyClass obj) 
{ 
    if (obj == null) { 
     return false; 
    } 
    else { 
     return (this._data != null && this._data.Equals(obj._data)) 
         || obj._data == null; 
    } 
} 

public override bool Equals(object obj) 
{ 
    if (obj == null || !(obj is MyClass)) { 
     return false; 
    } 
    else { 
     return this.Equals((MyClass)obj); 
    } 
} 

public override int GetHashCode() { 
    return this._data == null ? 0 : this._data.GetHashCode(); 
} 
+0

Haklısınız. Bu "Eşit" in arkasındaki kavramları kanıtlamak için sadece "kanonik" bir uygulamadır. "Gerçek" uygulamam genellikle a.Equals (b) yerine Equals (a, b) kullanılarak uygulanır. –

İlgili konular