当前位置:  开发笔记 > 编程语言 > 正文

重载运算符==与Equals()

如何解决《重载运算符==与Equals()》经验,为你挑选了6个好方法。

我正在开发一个C#项目,直到现在,我已经使用了不可变对象和工厂来确保Foo始终可以比较类型对象的相等性==.

Foo创建后无法更改对象,并且工厂始终为给定的参数集返回相同的对象.这很好用,在整个代码库中我们假设它==始终用于检查相等性.

现在我需要添加一些引入边缘情况的功能,但这并不总是有效.最简单的方法是operator ==为该类型重载,以便项目中的其他代码都不需要更改.但这让我感觉像代码味道:重载operator ==并且Equals不仅仅是看起来很奇怪,而且我习惯于==检查引用相等性的约定,并Equals检查对象的相等性(或任何术语).

这是一个合理的问题,还是我应该继续超载operator ==



1> Samuel Neff..:

重载 ==覆盖 Equals 之间存在很大差异.

当你有表达式

if (x == y) {

将用于比较变量x和y的方法在编译时决定.这是运算符重载.声明x和y时使用的类型用于定义用于比较它们的方法.x和y中的实际类型(即子类或接口实现)是无关紧要的.考虑以下.

object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference

if (x == y) { // evaluates to FALSE

和以下

string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference

if (x == y) { // evaluates to TRUE

这表明用于声明变量x和y的类型用于确定用于评估==的方法.

相比之下,Equals是在运行时根据变量x中的实际类型确定的.Equals是Object上的一个虚方法,其他类型可以并且确实覆盖它.因此,以下两个例子都评估为真.

object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference

if (x.Equals(y)) { // evaluates to TRUE

和以下

string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference

if (x.Equals(y)) { // also evaluates to TRUE


哇,这是.NET设计中一个可怕的蠢货.因为我使用对象x而不是字符串x来定义我的变量,两个字符串不相等的想法是奖品级代码气味.谢谢你这么好解释.

2> McKay..:

我相信标准是对于大多数类型,.Equals检查对象相似性,并且运算符==检查引用相等性.

我认为最佳实践是,对于不可变类型,运算符==应该检查相似性,以及.Equals.如果你想知道它们是否真的是同一个对象,请使用.ReferenceEquals.有关此String示例,请参阅C#类.


不可以.参考类型的"标准"是指Equals en ==返回与RefernceEquals相同的值.不鼓励对非不可变类型重载.
另外,请注意这里的空值.如果x为null,则x.Equals(null)将抛出NRE,而null == x将起作用.
比尔,但这是一个非常好的标准.你想要一个`a!= b`的类型,但Collection类认为它们是重复的吗?

3> Mike Sackton..:

对于不可变类型,我认为==重载以支持值相等没有任何问题.我不认为我会覆盖==而不会覆盖Equals具有相同的语义.如果==由于某种原因确实覆盖并需要检查引用相等性,则可以使用Object.ReferenceEquals(a,b).

有关一些有用的指导,请参阅此Microsoft文章



4> Henk Holterm..:

它绝对有气味.超载时==,你应该确保这两个Equals()GetHashCode()也是一致的.请参阅MSDN准则.

而这似乎没问题的唯一原因是你将你的类型描述为不可变的.



5> John..:

示例显示如何根据MSFT指南(如下)实现此目的.注意,当覆盖Equals时,您还需要覆盖GetHashCode().希望这有助于人们.

public class Person
{
    public Guid Id { get; private set; }

    public Person(Guid id)
    {
        Id = id;
    }

    public Person()
    {
        Id = System.Guid.NewGuid();
    }

    public static bool operator ==(Person p1, Person p2)
    {
        bool rc;

        if (System.Object.ReferenceEquals(p1, p2))
        {
            rc = true;
        }
        else if (((object)p1 == null) || ((object)p2 == null))
        {
            rc = false;
        }
        else
        {
            rc = (p1.Id.CompareTo(p2.Id) == 0);
        }

        return rc;
    }

    public static bool operator !=(Person p1, Person p2)
    {
        return !(p1 == p2);
    }

    public override bool Equals(object obj)
    {
        bool rc = false;
        if (obj is Person)
        {
            Person p2 = obj as Person;
            rc = (this == p2);
        }
        return rc;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}


如果p1和p2都为空,则ReferenceEquals将返回true.因此,布尔OR代码将永远不会执行,操作符将按预期返回true.

6> Ykok..:

根据Microsoft自己的最佳实践,Equals方法的结果和equals(==)重载应相同。

CA2224:重载等于运算符等于


在几乎所有情况下,当一个人超载静态绑定的==时,也应该覆盖虚拟的Equals成员,但反之则不成立。对于*密封的*类型,它们应该只重载==`,它们的行为非常类似于值(“ String”的方式),但是对于未密封的类型,通常应该覆盖“ Equals”。注意,许多程序员期望将==运算符应用于除string之外的任何其他类类型是检查引用是否相等的快捷方式。
推荐阅读
kikokikolove
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有