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

问题描述 投票:0回答:4

我希望我的

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

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

所以我的下一个问题是:.NET 框架的哪些函数/类使用

Object.Equals()
?我应该首先使用它吗?

c# .net equals equality iequatable
4个回答
265
投票

主要原因是性能。当 .NET 2.0 中引入泛型时,他们能够添加一堆简洁的类,例如

List<T>
Dictionary<K,V>
HashSet<T>
等。这些结构大量使用
GetHashCode
Equals
。但对于值类型,这需要装箱。
IEquatable<T>
让结构实现强类型
Equals
方法,因此不需要装箱。因此,在将值类型与泛型集合一起使用时,性能会更好。

引用类型没有那么多好处,但

IEquatable<T>
实现确实可以让您避免来自
System.Object
的强制转换,如果频繁调用,这可能会产生影响。

正如 Jared Parson 的博客所述,您必须仍然实施标准

Object.Equals
Object.GetHashcode
覆盖。


56
投票

根据MSDN

如果您实施

IEquatable<T>
,您 还应该重写基类 的实施
Object.Equals(Object)
GetHashCode
以便他们的行为保持一致 与
IEquatable<T>.Equals
的 方法。如果你覆盖
Object.Equals(Object)
,你被覆盖了 实现也在调用中调用 到类上的静态
Equals(System.Object,
  System.Object)
方法。 这确保了所有调用
Equals
方法返回一致 结果。

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

从逻辑的角度来看,实现接口也更好。重写该对象并不能真正告诉任何人您的类实际上是相等的。覆盖可能只是一个不执行任何操作的类或浅层实现。使用该接口明确表示:“嘿,这个东西对于相等性检查是有效的!”这只是更好的设计。


36
投票

用一个实际的例子来扩展乔什所说的内容。 +1 给乔什 - 我正要在我的答案中写同样的内容。

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() 方法,该方法可以开箱即用地用于我的所有派生类。


2
投票

如果我们调用

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

© www.soinside.com 2019 - 2024. All rights reserved.