IEquatable与重写Object.Equals()有什么区别?

时间:2010-04-29 05:12:41

标签: c# .net equals equality iequatable

我希望我的Food类能够在等于Food的另一个实例时进行测试。我稍后会对List使用它,我想使用它的List.Contains()方法。我应该实施IEquatable<Food>还是仅覆盖Object.Equals()?来自MSDN:

  

此方法通过确定相等性   使用默认的相等比较器,   由对象定义   实施   用于T的IEquatable.Equals方法   (列表中的值类型)。

所以我的下一个问题是:.NET框架的哪些函数/类使用Object.Equals()?我应该首先使用它吗?

4 个答案:

答案 0 :(得分:183)

主要原因是表现。当在.NET 2.0中引入泛型时,他们能够添加一些简洁的类,例如List<T>Dictionary<K,V>HashSet<T>等。这些结构大量使用{{1} }和GetHashCode。但对于价值类型,这需要拳击。 Equals允许结构实现强类型IEquatable<T>方法,因此不需要装箱。因此,在将值类型与泛型集合一起使用时,可以获得更好的性能。

参考类型没有那么多受益,但是Equals实现确实可以让你避免来自IEquatable<T>的强制转换,如果频繁调用它会产生影响。

Jared Parson's blog所述,您仍然必须实现对象覆盖。

答案 1 :(得分:43)

根据MSDN

  

如果您实施IEquatable(T),那么   还应该覆盖基类   的实现   Object.Equals(Object)GetHashCode   这样他们的行为是一致的   与IEquatable(T).Equals的那个   方法。如果你覆盖   Object.Equals(Object),你被覆盖了   在调用中也调用实现   到你班级的静态Equals(System.Object, System.Object)方法。   这确保了所有的调用   Equals方法返回一致   结果

所以似乎两者之间没有真正的功能差异,除了可以根据类的使用方式调用其中任何一个。从性能的角度来看,最好使用通用版本,因为没有与之相关的装箱/拆箱惩罚。

从逻辑角度来看,实现界面也更好。覆盖对象并不能真正告诉任何人你的类实际上是等同的。覆盖可能只是一个无用的类或浅实现。使用界面明确地说,“嘿,这个东西对于等式检查是有效的!”这只是更好的设计。

答案 2 :(得分:26)

用一个实际的例子来扩展乔希所说的话。 +1给Josh - 我的答案也是这样写的。

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

这样,我可以重复使用Equals()方法,该方法适用于所有派生类。

答案 3 :(得分:0)

如果我们调用object.Equals,它将迫使对值类型进行昂贵的装箱。在对性能敏感的情况下,这是不希望的。解决方案是使用IEquatable<T>

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

IEquatable<T>背后的想法是,它产生与object.Equals相同的结果,但速度更快。约束where T : IEquatable<T>必须与以下通用类型一起使用。

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

否则,它将绑定到slower object.Equals()