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

发布于 2024-08-30 12:26:43 字数 409 浏览 4 评论 0原文

我希望我的 Food 类能够在它等于 Food 的另一个实例时进行测试。稍后我将针对 List 使用它,并且我想使用它的 List.Contains() 方法。我应该实现 IEquatable 还是只重写 Object.Equals()?来自 MSDN:

此方法通过以下方式确定相等性 使用默认的相等比较器, 由对象的定义 的实施 T 的 IEquatable.Equals 方法 (列表中值的类型)。

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

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:

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).

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

北渚 2024-09-06 12:26:43

主要原因是性能。当 .NET 2.0 中引入泛型时,他们能够添加一堆简洁的类,例如 ListDictionaryHashSet< ;T> 等。这些结构大量使用 GetHashCodeEquals。但对于值类型,这需要装箱。 IEquatable 让结构实现强类型 Equals 方法,因此不需要装箱。因此,在将值类型与泛型集合一起使用时,性能会更好。

引用类型没有那么多好处,但 IEquatable 实现确实可以让您避免来自 System.Object 的强制转换,如果频繁调用,这可能会产生影响。

Jared Parson 的博客 不过,您必须仍然实现标准 Object.EqualsObject.GetHashcode< /代码> 覆盖。

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.

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.

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

执妄 2024-09-06 12:26:43

根据 MSDN

如果您实现 IEquatable,您
还应该重写基类
的实施
Object.Equals(Object)GetHashCode
以便他们的行为保持一致
IEquatable.Equals
方法。如果你覆盖
Object.Equals(Object),您的重写
实现也在调用中调用
到静态 Equals(System.Object,
System.Object)
类上的方法。
这确保了所有调用
Equals 方法返回一致
结果。

因此,两者之间似乎没有真正的功能差异,只是可以根据类的使用方式来调用其中一个。从性能的角度来看,最好使用通用版本,因为没有与之相关的装箱/拆箱惩罚。

从逻辑的角度来看,实现接口也更好。重写该对象并不能真正告诉任何人您的类实际上是相等的。覆盖可能只是一个不执行任何操作的类或浅层实现。使用该接口明确表示:“嘿,这个东西对于相等性检查是有效的!”这只是更好的设计。

According to the 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.

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.

|煩躁 2024-09-06 12:26:43

用一个实际的例子来扩展乔希的说法。 +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() 方法,该方法可以开箱即用地用于我的所有派生类。

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

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.

拔了角的鹿 2024-09-06 12:26:43

如果我们调用object.Equals,它会强制对值类型进行昂贵的装箱。这在性能敏感的场景中是不可取的。解决方案是使用 IEquatable

public interface IEquatable<T>
{
  bool Equals (T other);
}

IEquatable 背后的想法是,它提供与 object.Equals 相同的结果,但速度更快。约束 where T : IEquatable 必须与如下泛型类型一起使用。

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()

If we call object.Equals, it forces to expensive boxing on value types. This is undesirable in performance-sensitive scenarios. The solution is to use 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. The constrain where T : IEquatable<T> must be used with generic types like below.

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().

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文