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

时间:2023-01-24 16:11:51

I want my Food class to be able to test whenever it is equal to another instance of Food. I will later use it against a List, and I want to use its List.Contains() method. Should I implement IEquatable<Food> or just override Object.Equals()? From MSDN:

我想让我的食物类能够在它等于另一个食物实例时进行测试。稍后我将在列表中使用它,我想使用它的List. contains()方法。我是否应该实现IEquatable 或者只是重写Object.Equals()?从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).

该方法通过使用默认的相等比较器来确定相等,该比较器由对象的IEquatable实现定义。等于T的方法(列表中值的类型)。

So my next question is: which functions/classes of the .NET framework make use of Object.Equals()? Should I use it in the first place?

所以我的下一个问题是:.NET框架的哪些函数/类使用Object.Equals()?我应该首先使用它吗?

3 个解决方案

#1


150  

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. But for value types this required boxing. IEquatable<T> lets a structure implement a strongly typed Equals method so no boxing is required. Thus much better performance when using value types with generic collections.

主要原因是性能。当在。net 2.0中引入泛型时,它们可以添加一系列简洁的类,比如List 、Dictionary 、HashSet 等等。但是对于值类型,这需要装箱。IEquatable 允许结构实现强类型的Equals方法,因此不需要装箱。因此,在使用具有泛型集合的值类型时,性能会更好。 、v>

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 实现确实可以避免系统强制类型转换。对象,如果被频繁调用,就会有不同。

As noted on Jared Parson's blog though, you still must implement the Object overrides.

正如Jared Parson在博客中提到的,您仍然必须实现对象重写。

#2


35  

According to the MSDN:

根据MSDN:

If you implement IEquatable(T), you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable(T).Equals method. If you do override Object.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. This ensures that all invocations of the Equals method return consistent results.

如果您实现了IEquatable(T),您还应该重写objec . equals (Object)和GetHashCode的基类实现,以便它们的行为与IEquatable(T)的行为一致。=方法。如果您确实重写Object.Equals(Object),那么您重写的实现在调用静态Equals(System)时也会被调用。对象,System.Object类上的方法。这确保了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, its 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.

从逻辑的角度来看,实现接口也更好。重写对象并不能真正告诉任何人您的类实际上是可等同的。覆盖可能只是一个不做任何事情的类或一个浅显的实现。使用这个接口显式地说,“嘿,这个东西对相等检查是有效的!”这是更好的设计。

#3


21  

Extending what Josh said with a practical example. +1 to Josh - I was about to write the same in my answer.

用一个实际的例子来扩展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() { }
}

This way, I have re-usable Equals() method that works out of the box for all my derived classes.

这样,我就有了可重用的Equals()方法,它适用于所有派生类。

#1


150  

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. But for value types this required boxing. IEquatable<T> lets a structure implement a strongly typed Equals method so no boxing is required. Thus much better performance when using value types with generic collections.

主要原因是性能。当在。net 2.0中引入泛型时,它们可以添加一系列简洁的类,比如List 、Dictionary 、HashSet 等等。但是对于值类型,这需要装箱。IEquatable 允许结构实现强类型的Equals方法,因此不需要装箱。因此,在使用具有泛型集合的值类型时,性能会更好。 、v>

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 实现确实可以避免系统强制类型转换。对象,如果被频繁调用,就会有不同。

As noted on Jared Parson's blog though, you still must implement the Object overrides.

正如Jared Parson在博客中提到的,您仍然必须实现对象重写。

#2


35  

According to the MSDN:

根据MSDN:

If you implement IEquatable(T), you should also override the base class implementations of Object.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable(T).Equals method. If you do override Object.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. This ensures that all invocations of the Equals method return consistent results.

如果您实现了IEquatable(T),您还应该重写objec . equals (Object)和GetHashCode的基类实现,以便它们的行为与IEquatable(T)的行为一致。=方法。如果您确实重写Object.Equals(Object),那么您重写的实现在调用静态Equals(System)时也会被调用。对象,System.Object类上的方法。这确保了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, its 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.

从逻辑的角度来看,实现接口也更好。重写对象并不能真正告诉任何人您的类实际上是可等同的。覆盖可能只是一个不做任何事情的类或一个浅显的实现。使用这个接口显式地说,“嘿,这个东西对相等检查是有效的!”这是更好的设计。

#3


21  

Extending what Josh said with a practical example. +1 to Josh - I was about to write the same in my answer.

用一个实际的例子来扩展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() { }
}

This way, I have re-usable Equals() method that works out of the box for all my derived classes.

这样,我就有了可重用的Equals()方法,它适用于所有派生类。