C# 什么';IEquatable和仅覆盖Object.Equals()之间的区别是什么?
我希望我的C# 什么';IEquatable和仅覆盖Object.Equals()之间的区别是什么?,c#,.net,equals,equality,iequatable,C#,.net,Equals,Equality,Iequatable,我希望我的Food类能够在与Food的另一个实例相等时进行测试。稍后,我将对列表使用它,我想使用它的List.Contains()方法。我应该实现IEquatable还是只重写Object.Equals()?从MSDN: 此方法通过以下方式确定相等性: 使用默认的相等比较器, 由对象的 实施 T的等式方法 (列表中值的类型) 所以我的下一个问题是:.NETFramework的哪些函数/类使用了Object.Equals()?我应该首先使用它吗?主要原因是性能。当泛型在.NET 2.0中引入时,它
Food
类能够在与Food
的另一个实例相等时进行测试。稍后,我将对列表使用它,我想使用它的List.Contains()
方法。我应该实现IEquatable
还是只重写Object.Equals()
?从MSDN:
此方法通过以下方式确定相等性:
使用默认的相等比较器,
由对象的
实施
T的等式方法
(列表中值的类型)
所以我的下一个问题是:.NETFramework的哪些函数/类使用了
Object.Equals()
?我应该首先使用它吗?主要原因是性能。当泛型在.NET 2.0中引入时,它们能够添加一系列整洁的类,如List
,Dictionary
,HashSet
,等等。这些结构大量使用GetHashCode
和Equals
。但对于值类型,这需要装箱IEquatable
允许结构实现强类型的Equals
方法,因此不需要装箱。因此,在将值类型与泛型集合一起使用时,性能会更好
引用类型没有那么大的好处,但是IEquatable
实现确实让您避免了System.Object
的强制转换,如果频繁调用它,则会产生不同的效果
但是,如上所述,您必须仍然实现标准的对象。Equals
和对象。GetHashcode
覆盖。根据:
如果实现了IEquatable
,则
也应该重写基类
实现
Object.Equals(Object)
和GetHashCode
所以他们的行为是一致的
与i相等。等于
方法。如果你真的超控
Object.Equals(Object)
,您的
在调用中也调用实现
对于静态等于(System.Object,
对象)
方法。
这确保了
等于
方法返回一致的
结果
因此,这两个类之间似乎没有真正的功能区别,只是可以根据类的使用方式调用其中一个。从性能角度来看,最好使用通用版本,因为它没有装箱/拆箱惩罚
从逻辑的角度来看,实现接口也更好。重写对象并不会真正告诉任何人您的类实际上是可平等的。重写可能只是一个不做任何事情的类或一个浅层实现。使用接口明确地说,“嘿,这个东西对于等式检查是有效的!”这只是更好的设计。用一个实际的例子扩展了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() { }
}
公共抽象类EntityBase:IEquatable
{
公共EntityBase(){}
#区域可容纳成员
公共布尔等于(EntityBase其他)
{
//使用派生类实例上的反射实现相等。
返回true;
}
公共覆盖布尔等于(对象对象对象)
{
返回此.Equals(obj作为EntityBase);
}
#端区
}
公共类作者:EntityBase
{
公共作者(){}
}
公共类书:EntityBase
{
公共图书(){}
}
这样,我就有了一个可重用的Equals()方法,它对我所有的派生类都是开箱即用的。如果我们调用object.Equals
,它会强制对值类型进行昂贵的装箱。这在性能敏感的场景中是不可取的。解决方案是使用IEquatable
否则,它将绑定到较慢的object.Equals()
引用类型之间是否有强制转换?我一直认为,当您从一种对象向另一种对象分配一些不明显的强制转换时,强制转换只是您对编译器所做的“语句”。这是在编译后,代码甚至不知道那里有一个强制转换,这在C++中是正确的,但不是.NET语言,它强制类型安全。存在运行时强制转换,如果强制转换未成功,将引发异常。因此,有一个小的运行时罚款支付铸造。编译器可以优化上传,例如对象o=(对象)“string”;但是向下转换-string s=(string)o;-必须在运行时发生。我明白了。碰巧你有什么地方可以让我获得关于.NET的那种“更深入”的信息?谢谢我建议大家通过杰夫·里克特的《C#》和乔恩·斯基特的《C#纵深》推荐CLR。至于博客,Wintellect博客很好,msdn博客等等。IEquatable
接口除了提醒开发人员在类或结构中包含一个public bool Equals(T other)
成员之外,还有什么作用吗?接口的存在与否在运行时没有区别。Equals
的重载似乎是所有必要的。只需再问一个问题。使用“obj作为EntityBase”而不是(EntityBase)obj有什么好处?只是风格问题还是有任何优势?在“obj作为EntityBase”的情况下-如果obj不是EntityBase类型,它将通过“null”并继续,没有任何错误或异常,但如果是“(EntityBase)obj”,它将强制尝试将obj强制转换为EntityBase,如果obj不是EntityBase类型,它将抛出InvalidCastException。是的,“as”只能应用于引用类型。Josh指向Jared Par博客的链接似乎表明您还需要覆盖GetHashCode。不是这样吗?我真的没有得到您的实现提供的额外价值。您能澄清抽象基类解决的问题吗?@Amicable-是的,每当您重写Object.Equals(Object)时,您还必须重写GetHashCode以便容器工作。结构肯定应该实现
public interface IEquatable<T>
{
bool Equals (T other);
}
public class Test<T> where T : IEquatable<T>
{
public bool IsEqual (T a, T b)
{
return a.Equals (b); // No boxing with generic T
}
}