IEquatable ile sadece geçersiz kılınan Object.Equals () arasındaki fark nedir?


185

FoodSınıfımın başka bir örneğine eşit olduğunda test yapabilmesini istiyorum Food. Daha sonra bir Listeye karşı kullanacağım ve List.Contains()yöntemini kullanmak istiyorum . Uygulamalı mıyım IEquatable<Food>yoksa sadece geçersiz Object.Equals()mi bırakmalıyım ? MSDN'den:

Bu yöntem, nesnenin T için IEquatable.Equals yöntemini (listedeki değerlerin türü) uygulamasını tanımladığı gibi, varsayılan eşitlik karşılaştırıcısını kullanarak eşitliği belirler.

Bir sonraki sorum şu: .NET framework'ün hangi işlevleri / sınıflarını kullanıyor Object.Equals()? İlk etapta mı kullanmalıyım?


3
Burada çok iyi bir açıklama blogs.msdn.com/b/jaredpar/archive/2009/01/15/…
nawfal

Yanıtlar:


214

Ana sebep performanstır. Jenerik .NET 2.0 tanıtıldı onlar gibi düzgün sınıfların bir demet ekleyebildik List<T>, Dictionary<K,V>, HashSet<T>vb Bu yapılar çokça kullanan GetHashCodeve Equals. Ancak değer türleri için bu boks gerekliydi. IEquatable<T>bir yapının güçlü bir şekilde yazılmış bir Equalsyöntem uygulamasını sağlar, böylece boks gerekmez. Böylece, genel koleksiyonlarla değer türlerini kullanırken çok daha iyi performans.

Referans türleri çok fazla fayda sağlamaz, ancak IEquatable<T>uygulama, System.Objectsık sık çağrıldığında fark yaratabilecek bir yayından kaçınmanıza izin verir .

Yine de Jared Parson'un blogunda belirtildiği gibi , Nesne geçersiz kılmalarını uygulamanız gerekir.


Referans türleri arasında döküm var mı? Ben her zaman, bir tür nesneden diğerine belli olmayan açık dökümler atadığınızda, çeviricilerin derleyiciye yaptığınız "ifadeler" olduğunu düşündüm. Bu, derledikten sonra, kodun orada bir döküm olduğunu bile bilmeyecek.
devoured elysium

7
Bu, C ++ için geçerlidir ancak tür güvenliğini zorlayan .NET dilleri için geçerli değildir. Bir çalışma zamanı kademesi var ve yayın başarılı olmazsa bir istisna atılır. Yani döküm için ödemek için küçük bir çalışma zamanı cezası var. Derleyici yukarı çıkışları optimize edebilir. Örneğin object o = (object) "string"; Ama küçümseme - string s = (string) o; - çalışma zamanında gerçekleşmelidir.
Josh

1
Anlıyorum. Şans eseri ben .NET hakkında bu tür "daha derin" bilgi alabilirsiniz herhangi bir yer var mı? Teşekkürler!
devoured elysium

7
Jeff Richter tarafından CL # ve Jon Skeet tarafından Derinlik C # ile CLR öneriyoruz. Bloglara gelince, Wintellect blogları iyi, msdn blogları vb.
Josh

Does IEquatable<T>arayüz do şey daha bir dahil etmek için bir geliştirici hatırlatmak public bool Equals(T other) sınıf veya yapı elemanına? Arayüzün varlığı veya yokluğu çalışma zamanında fark etmez. Aşırı yüklenmesi Equalsgereken tek şey gibi görünecektir.
mikemay

48

Göre MSDN :

Eğer uygularsanız IEquatable<T>, ayrıca taban sınıf uygulamalarını geçersiz kılar Object.Equals(Object)ve GetHashCode böylece onların davranışları ile tutarlı olduğunu IEquatable<T>.Equals yöntemle. Geçersiz kılarsanız Object.Equals(Object), geçersiz kılınmış uygulamanız da Equals(System.Object, System.Object)sınıfınızdaki statik yönteme çağrılarda çağrılır . Bu, Equalsyöntemin tüm çağrılarının tutarlı sonuçlar döndürmesini sağlar.

Bu nedenle, sınıfın nasıl kullanıldığına bağlı olarak her ikisi de çağrılabilmesi dışında ikisi arasında gerçek bir fonksiyonel fark olmadığı görülmektedir. Performans açısından bakıldığında, genel sürümü kullanmak daha iyidir çünkü onunla ilişkili bir boks / kutudan çıkarma cezası yoktur.

Mantıksal bir bakış açısından, arayüzü uygulamak daha iyidir. Nesneyi geçersiz kılmak gerçekten kimseye sınıfınızın gerçekten eşit olduğunu söylemez. Geçersiz kılma sadece hiçbir şey yapma sınıfı veya sığ bir uygulama olabilir. Arayüzü açıkça kullanarak "Hey, bu şey eşitlik kontrolü için geçerlidir!" Sadece daha iyi bir tasarım.


9
Bir Sözlük veya benzer bir koleksiyonda anahtar olarak kullanılacaklarsa, yapılar kesinlikle iEquatable (kendiOwnType) yöntemini uygulamalıdır; büyük bir performans artışı sunacak. Devralınamayan sınıflar IEquatable (kendiOwnType'ları) uygulayarak hafif bir performans artışı alacaktır. Devralınabilen sınıflar // değil // IEquatable uygulamalıdır.
supercat

30

Josh'un söylediklerini pratik bir örnekle genişletmek. Josh'a +1 - Cevabımda aynısını yazmak üzereydim.

public abstract class EntityBase : IEquatable<EntityBase>
{
    public EntityBase() { }

    #region IEquatable<EntityBase> Members

    public bool Equals(EntityBase other)
    {
        //Generic implementation of equality using reflection on derived class instance.
        return true;
    }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as EntityBase);
    }

    #endregion
}

public class Author : EntityBase
{
    public Author() { }
}

public class Book : EntityBase
{
    public Book() { }
}

Bu şekilde, tüm türetilmiş sınıflarım için kutunun dışında çalışan yeniden kullanılabilir Equals () yöntemi var.


Sadece bir soru daha. (EntityBase) obj yerine "obj as EntityBase olarak" kullanmanın avantajı nedir? Sadece bir stil meselesi ya da herhangi bir avantajı var mı?
devoured elysium

22
"EntityBase olarak obj" durumunda - obj EntityBase türünde değilse, "null" iletir ve herhangi bir hata veya istisnasız devam eder, Ancak "(EntityBase) obj" durumunda, nesneyi zorla yayınlamaya çalışır ve EntityBase türünde değilse, InvalidCastException atar. Ve evet, "as" yalnızca referans türlerine uygulanabilir.
bu. __curious_geek

1
Josh'un Jared Par'ın bloguna bağlantısı GetHashCode'u da geçersiz kılmanız gerektiğini gösteriyor. Durum böyle değil mi?
Dostça

3
Uygulamanızın sağladığı ekstra değeri gerçekten alamıyorum. Soyut temel sınıfınızın çözdüğü sorunu açıklığa kavuşturabilir misiniz?
Mert Akcakaya

1
@Amicable - evet, Object.Equals (Object) öğesini her değiştirdiğinizde, kapların çalışması için GetHashCode'u da geçersiz kılmanız gerekir.
namford

0

Eğer object.Equalsararsak, değer türlerinde pahalı boks yapmaya zorlar. Performansa duyarlı senaryolarda bu istenmeyen bir durumdur. Çözüm kullanmaktır IEquatable<T>.

public interface IEquatable<T>
{
  bool Equals (T other);
}

Buradaki fikir IEquatable<T>, aynı sonucu object.Equalsancak daha hızlı vermesidir . Kısıtlama where T : IEquatable<T>aşağıdaki gibi genel tiplerle kullanılmalıdır.

public class Test<T> where T : IEquatable<T>
{
  public bool IsEqual (T a, T b)
  {
    return a.Equals (b); // No boxing with generic T
  }
}

aksi halde, bağlanır slower object.Equals().

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.