我希望我的Food
课程能够在等于的另一个实例时进行测试Food
。稍后将针对列表使用它,并且我想使用其List.Contains()
方法。我应该实施IEquatable<Food>
还是仅重写Object.Equals()
?从MSDN:
此方法通过使用默认的相等比较器确定相等,该比较器由对象的IEquatable.Equals方法实现,用于T(列表中值的类型)。
所以我的下一个问题是:.NET框架的哪些函数/类使用了Object.Equals()
?我应该首先使用它吗?
我希望我的Food
课程能够在等于的另一个实例时进行测试Food
。稍后将针对列表使用它,并且我想使用其List.Contains()
方法。我应该实施IEquatable<Food>
还是仅重写Object.Equals()
?从MSDN:
此方法通过使用默认的相等比较器确定相等,该比较器由对象的IEquatable.Equals方法实现,用于T(列表中值的类型)。
所以我的下一个问题是:.NET框架的哪些函数/类使用了Object.Equals()
?我应该首先使用它吗?
Answers:
主要原因是性能。当泛型在.NET 2.0中引入他们能够添加一堆整齐班如List<T>
,Dictionary<K,V>
,HashSet<T>
,等这些结构大量使用GetHashCode
和Equals
。但是对于值类型,这需要装箱。IEquatable<T>
使结构实现强类型Equals
方法,因此不需要装箱。因此,在将值类型与泛型集合一起使用时,性能会更好。
引用类型并没有带来太多好处,但是该IEquatable<T>
实现确实使您避免了强制转换,System.Object
如果频繁调用强制转换会有所不同。
正如Jared Parson的博客所述,您仍然必须实现Object覆盖。
IEquatable<T>
除了提醒开发人员public bool Equals(T other)
在类或结构中包含成员外,界面是否还要做其他事情 ?接口的存在与否在运行时没有区别。的超载Equals
似乎是所需要的。
根据MSDN:
如果实现了
IEquatable<T>
,你也应该重写的基类的实现Object.Equals(Object)
,并GetHashCode
让他们的行为与该一致的IEquatable<T>.Equals
方法。如果您重写Object.Equals(Object)
,则在Equals(System.Object, System.Object)
对类的静态方法的调用中也会调用被重写的实现。这样可以确保该Equals
方法的所有调用都返回一致的结果。
因此,似乎两者之间没有真正的功能差异,只是可以根据类的使用方式调用两者中的任何一个。从性能的角度来看,最好使用通用版本,因为没有与此相关的装箱/拆箱损失。
从逻辑的角度来看,最好实现该接口。覆盖该对象并不能真正告诉任何人您的类实际上是平等的。覆盖可能只是不执行任何操作的类或浅层的实现。使用该接口明确表示:“嘿,这对于相等性检查是有效的!” 这只是更好的设计。
用一个实际的例子来扩展Josh所说的。+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()方法,该方法对于我所有的派生类都可以使用。
如果调用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()
。