【问题标题】:Is overloading of the == operator necessary here?这里需要重载 == 运算符吗?
【发布时间】:2014-02-22 16:03:06
【问题描述】:

我认为 == 下面代码中的重载是不必要的,因为 == 如果未重载,则已经比较引用。请告知我的方式。应该用一个参数 Equals 和分别包含的 null 比较来完成?

public class Student
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override bool Equals(object param)
    {
    // If the cast is invalid, the result will be null
    Student student = param as Student;

    // Check if we have valid not null Student object
    if (student == null)
    {
        return false;
    }

    // Compare the reference type member fields
    if (!Object.Equals(this.Name, student.Name))
    {
        return false;
    }

    // Compare the value type member fields
    if (this.Age != student.Age)
    {
        return false;
    }
    return true;
    }

    public static bool operator ==(Student student1, Student student2)
    {
        return Student.Equals(student1, student2);
    }

    public static bool operator !=(Student student1, Student student2)
    {
        return !(Student.Equals(student1, student2));
    }

  ...

  }

【问题讨论】:

  • 添加语言标签。
  • 这是 c#....? SO上有很多种语言

标签: c# operator-overloading equals


【解决方案1】:

我认为 == 下面代码中的重载是不必要的,因为 == 如果没有重载,则已经比较引用。

是的,但关键是因为运算符已经重载,你可以比较值相等而不是引用标识。例如:

Student x = new Student { Name = "Jon", Age = 37 };
Student y = new Student { Name = "Jon", Age = 37 };

Console.WriteLine(x == y); // Prints True

如果没有运算符重载,上面的代码将打印False,因为xy 的值引用了不同的对象。

这有时比显式调用Equals 方法更方便。

因此,虽然在这里重载== 并不是严格必要(因为可以通过其他方式实现相同的结果),但它确实会影响行为。以任何方式为所有类型重载== 都不是一个好主意,但它可以使某些类型的事情变得更简单。例如,我很高兴string 重载==。幸运的是,关于何时超载== 是一个好主意的讨论超出了这个答案的范围 - 对于初学者来说,这是一个有争议的问题。我很少为类这样做,但几乎总是为值类型。 (从编写自定义值类型开始是非常罕见的。)一般的灰色区域是不可变的引用类型......

请注意,重载在操作数为正确的编译时类型时应用。例如:

Student x = new Student { Name = "Jon", Age = 37 };
object y = new Student { Name = "Jon", Age = 37 };

Console.WriteLine(x == y); // Prints False

这里没有使用重载,因为y 的编译时类型是object,而不是Student

另外,这是一个可变 类,它覆盖Equals,因此可能是GetHashCode,这是一个值得关注的问题。在实例可以以影响平等的方式更改的类中覆盖Equals 通常是一个坏主意。它不适用于使用相等和散列的集合。例如:

var dictionary = new Dictionary<Student, string>();
var student = new Student { Name = "Jon", Age = 37 };
dictionary[student] = "foo";
Console.WriteLine(dictionary.ContainsKey(student)); // True
dictionary.Name = "Bob";
Console.WriteLine(dictionary.ContainsKey(student)); // False
Console.WriteLine(dictionary.Keys.First() == student); // True!

由于名称已更改,因此哈希码已更改(我假设使用名称和年龄的相当简单的哈希码实现)。这意味着即使引用仍在字典中,正常的哈希检查也会失败。

如果您在将键添加到字典后 不对其进行更改也没关系,但可以这么说,这样的类型更容易发生意外。

【讨论】:

    【解决方案2】:

    不必要且适得其反。在 C# 中,== 应用于类类型的对象是为了检查身份,而不是值相等。将== 重载为equals 是令人困惑且不习惯的,并且可能会导致某些容器类型出现问题。

    【讨论】:

    • 是的。我的意思是它不像string 重载==,例如。不用等,它确实......
    • 主要是为了规范实习和非实习字符串的处理。有人可能会争辩说,不可变数据类型应该重载==,但即使这样也是一个滑坡。
    • 你有任何证据证明你的“主要是正常化”的说法吗?我以前从未见过这样的理由。作为一个反例,我看到 很多 来自 Java 开发人员的 Stack Overflow 问题,他们错误地使用 == 来比较字符串。我很高兴我们没有收到关于 C# 的这些问题,仅仅是因为 == 已超载。即使字符串实习从未发生过,情况也是如此。
    • 我同意不可变引用类型是最值得重载的类型 ==。
    • @JonSkeet:恕我直言,如果在没有明确支持的类型上使用== 是一个错误,并且引用相等性测试,Java 和(尤其是)C# 中的很多混淆是可以避免的需要使用其他一些不可重载的运算符。否则,关于 Sneftel 的说法,.NET 1.0 中除了String 之外还有多少类类型重载了==
    猜你喜欢
    • 1970-01-01
    • 2016-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多