212

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

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

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

4

4 回答 4

245

主要原因是性能。在 .NET 2.0 中引入泛型时,它们能够添加一堆整洁的类,例如List<T>Dictionary<K,V>HashSet<T>等。这些结构大量使用GetHashCodeEquals。但是对于值类型,这需要装箱。IEquatable<T>让结构实现强类型Equals方法,因此不需要装箱。因此,在将值类型与泛型集合一起使用时性能要好得多。

引用类型没有那么大的好处,但是IEquatable<T>实现确实可以让您避免强制转换,System.Object如果频繁调用它会产生影响。

正如Jared Parson 的博客所指出的,您仍然必须实现标准Object.EqualsObject.GetHashcode覆盖。

于 2010-04-29T05:20:43.583 回答
55

根据MSDN

如果您实现IEquatable<T>,您还应该覆盖 和 的基类实现, Object.Equals(Object)以便GetHashCode 它们的行为与IEquatable<T>.Equals 方法的行为一致。如果你做 override Object.Equals(Object),你的覆盖实现也会在调用Equals(System.Object, System.Object)你的类的静态方法时被调用。这确保了该Equals方法的所有调用都返回一致的结果。

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

从逻辑的角度来看,实现接口也更好。覆盖该对象并不能真正告诉任何人您的类实际上是平等的。覆盖可能只是一个什么都不做的类或浅层实现。使用接口明确地说,“嘿,这东西对相等检查有效!” 这只是更好的设计。

于 2010-04-29T05:22:53.860 回答
33

用一个实际的例子来扩展 Josh 所说的话。+1 to 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() 方法,该方法对我的所有派生类都是开箱即用的。

于 2010-04-29T05:33:54.770 回答
1

如果我们调用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().

于 2020-05-02T13:00:47.190 回答