C#运算符==:什么是标准做法(引用/值相等)

本文关键字:引用 运算符 什么 标准 | 更新日期: 2023-09-27 18:01:09

说明:

  • CCD_ 1比较两个对象的值
  • CCD_ 2比较了它们的参考文献

对于引用类型,默认情况下operator==比较引用,而对于值类型,它使用反射执行(AFAIK)等效的Equals()。

所以。在这种情况下,我需要通过两种引用类型的值来比较它们。我可以显式地调用CCD_ 4,或者我可以重载CCD_。

然而,重载operator==进行值比较有点违反了最小惊奇原则。另一方面,显式调用两个对象Equals看起来有些过头了。

这里的标准做法是什么?


我知道如何覆盖Equals()。问题是,重写operator==以测试引用类型上的相等性是否普遍接受,或者显式调用Equals/ReferenceEquals以显式指定您想要的比较是否普遍接受。

C#运算符==:什么是标准做法(引用/值相等)

什么是标准做法?

"标准做法"是,如果你想检查两个元素是否相等,而不是引用相等,你需要实现Equals()0,它引入了Equals(T other)方法,并覆盖GetHashCode。这样,就可以控制比较这两个对象的方式。通常,这也包括覆盖==!=运算符。

而对于值类型,它使用反射

仅当您的值类型具有引用类型的成员时。如果它都是值类型,它将对这两个对象进行一点比较:

// if there are no GC references in this object we can avoid reflection 
// and do a fast memcmp
if (CanCompareBits(this))
    return FastEqualsCheck(thisObj, obj);

问题是,是否普遍接受推翻运算符==测试引用类型上的值相等性

这真的取决于你在做什么。建议在重写Equals之后重写==运算符,因为您需要一致的行为值相等语义。这取决于您对两个对象之间相等的定义。

尽管如此,如果一个对象是可变的,那么进行值比较可能会导致两个对象被认为相等,但后来一个对象发生了变异的奇怪情况。这肯定应该根据具体情况进行分析。通常,覆盖Equals就足够了。

CCD_ 18执行两个对象的值比较。

这不是真的。object.Equals在值类型上的默认行为是使用它们的相等定义来比较每个字段,引用类型的默认行为则是比较它们的引用。它可以被重写以执行您希望它执行的任何操作。在这方面,它与ReferenceEquals()0运算符完全相同。

==运算符和Equals之间的唯一区别是,Equals将对第一个(而不是第二个)操作数执行虚拟调度,根据该对象的运行时类型查找方法的实现。==算子是完全静态绑定的;它只考虑两个操作数的编译时类型。除了绑定上的差异之外,两者都有相同的默认行为,并且都可以被覆盖以提供您想要的任何实现。

标准做法是始终确保Equalsoperator ==的行为与您的类型相同。如果重写Equals方法以更改相等语义,那么还应该重载==运算符以提供"完全相同的语义",反之亦然。

问题是,是否普遍接受推翻运算符==测试值相等

它取决于对象,如果对象是不可变的,则可以重写==运算符,否则不能(记住它们只是指南)

请参阅:Override Equals()and Operator==(C#编程指南)指南

默认情况下,运算符==通过确定两个引用是否指示相同的对象。因此,引用类型不必在中实现运算符==以便获得该功能当一个类型是不可变的时即实例中包含的数据不能更改,重载运算符==比较值相等而不是引用相等可能很有用,因为作为不可变对象只要它们具有相同的值,就可以被认为是相同的它在非可变类型中重写运算符==不是一个好主意

为代码赋予语义是一种很好的做法。所以,如果引用比较真的是你应该关心的事情,那么对你的类使用默认行为;否则,应该使用与应用程序上下文相关的逻辑进行比较。(具有所有相等成员(如EqualsGetHashCode和运算符)的一致行为)