我希望我的Food类能够在它等于另一个Food实例时进行测试。我稍后将对一个List使用它,并且我想使用它的List. contains()方法。我是否应该实现IEquatable<Food>或只是覆盖Object.Equals()?从MSDN:
这个方法用 使用默认的相等比较器, 由对象的属性定义 实施 IEquatable。T的等号方法 (列表中值的类型)。
所以我的下一个问题是:.NET框架的哪些函数/类使用了Object.Equals()?我应该首先使用它吗?
我希望我的Food类能够在它等于另一个Food实例时进行测试。我稍后将对一个List使用它,并且我想使用它的List. contains()方法。我是否应该实现IEquatable<Food>或只是覆盖Object.Equals()?从MSDN:
这个方法用 使用默认的相等比较器, 由对象的属性定义 实施 IEquatable。T的等号方法 (列表中值的类型)。
所以我的下一个问题是:.NET框架的哪些函数/类使用了Object.Equals()?我应该首先使用它吗?
当前回答
根据MSDN:
如果你实现IEquatable<T>,你 也应该重写基类吗 的实现 Object. equals (Object)和GetHashCode 这样他们的行为是一致的 与不等式<T>的值相对应。= 方法。如果你重写了 Object。equals (Object),你重写了 在调用中也调用实现 到静态等于(系统。对象, System.Object)方法。 的所有调用 Equals方法返回一致 结果。
因此,这两者之间似乎没有真正的功能差异,除了可以根据类的使用方式调用它们。从性能的角度来看,最好使用通用版本,因为没有与之相关的装箱/拆箱惩罚。
从逻辑的角度来看,实现接口也更好。重写对象并不能真正告诉任何人你的类实际上是相等的。重写可能只是一个什么都不做的类或一个浅实现。使用接口显式地表示,“嘿,这个东西对相等性检查有效!”这只是更好的设计。
其他回答
用一个实际的例子来扩展Josh说的话。+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()方法,它可以为我的所有派生类开箱即用。
根据MSDN:
如果你实现IEquatable<T>,你 也应该重写基类吗 的实现 Object. equals (Object)和GetHashCode 这样他们的行为是一致的 与不等式<T>的值相对应。= 方法。如果你重写了 Object。equals (Object),你重写了 在调用中也调用实现 到静态等于(系统。对象, System.Object)方法。 的所有调用 Equals方法返回一致 结果。
因此,这两者之间似乎没有真正的功能差异,除了可以根据类的使用方式调用它们。从性能的角度来看,最好使用通用版本,因为没有与之相关的装箱/拆箱惩罚。
从逻辑的角度来看,实现接口也更好。重写对象并不能真正告诉任何人你的类实际上是相等的。重写可能只是一个什么都不做的类或一个浅实现。使用接口显式地表示,“嘿,这个东西对相等性检查有效!”这只是更好的设计。
如果我们调用object。等于,它强制对值类型进行昂贵的装箱。这在对性能敏感的场景中是不可取的。解决方案是使用IEquatable<T>。
public interface IEquatable<T>
{
bool Equals (T other);
}
IEquatable<T>背后的思想是,它给出了与object相同的结果。等于,但更快。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
}
}
否则,它绑定到较慢的object.Equals()。
主要原因是性能。当泛型在。net 2.0中引入时,他们能够添加一堆整洁的类,如List<T>, Dictionary<K,V>, HashSet<T>等。这些结构大量使用GetHashCode和Equals。但是对于值类型,这需要装箱。IEquatable<T>允许结构实现强类型Equals方法,因此不需要装箱。因此,在与泛型集合一起使用值类型时,性能将大大提高。
引用类型没有那么多好处,但IEquatable<T>实现确实让您避免了来自System的强制转换。对象,如果频繁调用会产生不同。
正如Jared Parson的博客所指出的,你仍然必须实现标准对象。等号和对象。GetHashcode方法覆盖。