[英]What's the difference between IEquatable and just overriding Object.Equals()?
I want my Food
class to be able to test whenever it is equal to another instance of Food
.我希望我的
Food
类能够在它等于Food
另一个实例时进行测试。 I will later use it against a List, and I want to use its List.Contains()
method.稍后我将针对 List 使用它,并且我想使用它的
List.Contains()
方法。 Should I implement IEquatable<Food>
or just override Object.Equals()
?我应该实现
IEquatable<Food>
还是只覆盖Object.Equals()
? From MSDN:来自 MSDN:
This method determines equality by using the default equality comparer, as defined by the object's implementation of the IEquatable.Equals method for T (the type of values in the list).
此方法通过使用默认相等比较器来确定相等性,正如对象对 T(列表中值的类型)的 IEquatable.Equals 方法的实现所定义的那样。
So my next question is: which functions/classes of the .NET framework make use of Object.Equals()
?所以我的下一个问题是:.NET 框架的哪些函数/类使用
Object.Equals()
? Should I use it in the first place?我应该首先使用它吗?
The main reason is performance.主要原因是性能。 When generics were introduced in .NET 2.0 they were able to add a bunch of neat classes such as
List<T>
, Dictionary<K,V>
, HashSet<T>
, etc. These structures make heavy use of GetHashCode
and Equals
.在 .NET 2.0 中引入泛型时,它们能够添加一堆整洁的类,例如
List<T>
、 Dictionary<K,V>
、 HashSet<T>
等。这些结构大量使用GetHashCode
和Equals
。 But for value types this required boxing.但是对于值类型,这需要装箱。
IEquatable<T>
lets a structure implement a strongly typed Equals
method so no boxing is required. IEquatable<T>
允许结构实现强类型的Equals
方法,因此不需要装箱。 Thus much better performance when using value types with generic collections.因此,在将值类型与泛型集合一起使用时性能要好得多。
Reference types don't benefit as much but the IEquatable<T>
implementation does let you avoid a cast from System.Object
which can make a difference if it's called frequently.引用类型没有那么多好处,但
IEquatable<T>
实现确实让您避免了System.Object
的IEquatable<T>
,如果它被频繁调用,这可能会产生影响。
As noted on Jared Parson's blog though, you must still implement the standard Object.Equals
and Object.GetHashcode
overrides.不过,正如Jared Parson 的博客所述,您仍然必须实现标准的
Object.Equals
和Object.GetHashcode
覆盖。
According to the MSDN :根据MSDN :
If you implement
IEquatable<T>
, you should also override the base class implementations ofObject.Equals(Object)
andGetHashCode
so that their behavior is consistent with that of theIEquatable<T>.Equals
method.如果您实现
IEquatable<T>
,您还应该覆盖Object.Equals(Object)
和GetHashCode
的基类实现,以便它们的行为与IEquatable<T>.Equals
方法的行为一致。 If you do overrideObject.Equals(Object)
, your overridden implementation is also called in calls to the staticEquals(System.Object, System.Object)
method on your class.如果您确实覆盖
Object.Equals(Object)
,则您的覆盖实现也会在对类上的静态Equals(System.Object, System.Object)
方法的调用中调用。 This ensures that all invocations of theEquals
method return consistent results.这可确保
Equals
方法的所有调用返回一致的结果。
So it seems that there's no real functional difference between the two except that either could be called depending on how the class is used.因此,这两者之间似乎没有真正的功能差异,只是可以根据类的使用方式调用两者。 From a performance standpoint, it's better to use the generic version because there's no boxing/unboxing penalty associated with it.
从性能的角度来看,最好使用通用版本,因为没有与之相关的装箱/拆箱惩罚。
From a logical standpoint, it's also better to implement the interface.从逻辑的角度来看,实现接口也更好。 Overriding the object doesn't really tell anyone that your class is actually equatable.
覆盖该对象并没有真正告诉任何人你的类实际上是等价的。 The override may just be a do nothing class or a shallow implementation.
覆盖可能只是一个什么都不做的类或一个浅层的实现。 Using the interface explicitly says, "Hey, this thing is valid for equality checking!"
使用接口明确地说,“嘿,这东西对等式检查有效!” It's just better design.
这只是更好的设计。
Extending what Josh said with a practical example.用一个实际的例子来扩展乔希所说的。 +1 to Josh - I was about to write the same in my answer.
+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() { }
}
This way, I have re-usable Equals() method that works out of the box for all my derived classes.这样,我就有了可重用的 Equals() 方法,该方法对我的所有派生类都是开箱即用的。
If we call object.Equals
, it forces to expensive boxing on value types.如果我们调用
object.Equals
,它会强制对值类型进行昂贵的装箱。 This is undesirable in performance-sensitive scenarios.这在性能敏感的场景中是不可取的。 The solution is to use
IEquatable<T>
.解决方案是使用
IEquatable<T>
。
public interface IEquatable<T>
{
bool Equals (T other);
}
The idea behind IEquatable<T>
is that it gives the same result as object.Equals
but more quickly.背后的想法
IEquatable<T>
的是,它提供了相同的结果object.Equals
但更迅速。 The constrain where T : IEquatable<T>
must be used with generic types like below.约束
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
}
}
otherwise, it binds to slower object.Equals()
.否则,它绑定到
slower object.Equals()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.