C# 重载 operator== 与 Equals()

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1766492/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:38:06  来源:igfitidea点击:

Overloading operator== versus Equals()

c#operator-overloadingequals

提问by JSB????

I'm working on a C# project on which, until now, I've used immutable objects and factories to ensure that objects of type Foocan always be compared for equality with ==.

我正在处理一个 C# 项目,到目前为止,我一直使用不可变对象和工厂来确保类型的对象Foo始终可以与==.

Fooobjects can't be changed once created, and the factory always returns the same object for a given set of arguments. This works great, and throughout the code base we assume that ==always works for checking equality.

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

Now I need to add some functionality that introduces an edge case for which this won't always work. The easiest thing to do is to overload operator ==for that type, so that none of the other code in the project needs to change. But this strikes me as a code smell: overloading operator ==and not Equalsjust seems weird, and I'm used to the convention that ==checks reference equality, and Equalschecks object equality (or whatever the term is).

现在我需要添加一些引入边缘情况的功能,这并不总是有效。最简单的做法是重载operator ==该类型,这样项目中的其他代码都不需要更改。但这给我留下了代码味道:重载operator ==而不Equals只是看起来很奇怪,而且我已经习惯了==检查引用相等性和Equals检查对象相等性(或任何术语)的约定。

Is this a legitimate concern, or should I just go ahead and overload operator ==?

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

采纳答案by McKay

I believe the standard is that for most types, .Equals checks object similarity, and operator ==checks reference equality.

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

I believe best practice is that for immutable types, operator ==should be checking for similarity, as well as .Equals. And if you want to know if they really are the same object, use .ReferenceEquals. See the C# Stringclass for an example of this.

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

回答by Mike Sackton

For immutable types I don't think there is anything wrong with having ==overloaded to support value equality. I don't think I'd override ==without overriding Equalsto have the same semantics however. If you do override ==and need to check reference equality for some reason, you can use Object.ReferenceEquals(a,b).

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

See this Microsoft article for some useful guidelines

有关一些有用的指南,请参阅这篇Microsoft 文章

回答by Henk Holterman

It definitely smells. When overloading ==you should make sure that both Equals()and GetHashCode()are also consistent. See the MSDN guidelines.

它肯定有味道。重载时,==您应该确保Equals()GetHashCode()也是一致的。请参阅MSDN 指南

And the only reason that this seems OK at all is that you describe your type as immutable.

这看起来还不错的唯一原因是你将你的类型描述为不可变的。

回答by Samuel Neff

There's a big difference between overloading==and overridingEquals.

重载==覆盖Equals之间有很大的不同。

When you have the expression

当你有表情

if (x == y) {

The method that will be used to compare variables x and y is decided at compiletime. This is operator overloading. The type used when declaring x and y is used to define which method is used to compare them. The actual type within x and y (i.e., a subclass or interface implementation) is irrelevant. Consider the following.

用于比较变量 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

and the following

和以下

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

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

This demonstrates that the type used to declare the variables x and y is used to determine which method is used to evaluate ==.

这表明用于声明变量 x 和 y 的类型用于确定使用哪种方法计算 ==。

By comparison, Equals is determined at runtimebased on the actual type within the variable x. Equals is a virtual method on Object that other types can, and do, override. Therefore the following two examples both evaluate to true.

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

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

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

and the following

和以下

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

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

回答by Ykok

According to Microsofts own best practises the outcome of the Equals method and the equals (==) overload should be the same.

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

CA2224: Override equals on overloading operator equals

CA2224:重载运算符等于时覆盖等于

回答by John

Sample showing how to implement this according to MSFT guidelines(below). Notice, when overriding Equals you also need to override GetHashCode(). Hope this helps folks.

示例显示了如何根据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();
    }
}