C#运算符==:什么是标准实践(参考/值相等)?

C#运算符==:什么是标准实践(参考/值相等)?,c#,C#,说明: Equals()比较两个对象的值 ReferenceEquals()比较它们的引用 对于引用类型,operator==默认情况下比较引用,而对于值类型,它使用反射执行(AFAIK)相等于Equals()的操作 所以。在这种情况下,我需要根据两种引用类型的值来比较它们。我可以显式调用Equals()或重载操作符==,以执行所需的比较 然而,重载操作符==进行值比较有点违反了最小惊讶原则。另一方面,显式调用两个对象Equals看起来太过分了 这里的标准做法是什么 我知道如何重写Equa

说明:

  • Equals()
    比较两个对象的值
  • ReferenceEquals()
    比较它们的引用
对于引用类型,
operator==
默认情况下比较引用,而对于值类型,它使用反射执行(AFAIK)相等于Equals()的操作

所以。在这种情况下,我需要根据两种引用类型的值来比较它们。我可以显式调用
Equals()
或重载
操作符==
,以执行所需的比较

然而,重载
操作符==
进行值比较有点违反了最小惊讶原则。另一方面,显式调用两个对象
Equals
看起来太过分了

这里的标准做法是什么


我知道如何重写
Equals()
。问题是,覆盖
运算符==
来测试引用类型上的值是否等于是否是普遍接受的做法,还是普遍接受的做法是显式调用Equals/ReferenceEquals来显式指定所需的比较

什么是标准实践

“标准实践”是,如果要检查两个元素是否相等,而这两个元素不是引用相等,则需要实现
IEquatable
,它引入了
Equals(t other)
方法,并重写
GetHashCode
。这样,您就可以控制比较这两个对象的方式。通常,这包括覆盖
==
=操作符

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

仅当值类型具有引用类型的成员时。如果都是值类型,则:

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

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

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

问题是,是否可以普遍接受否决 运算符==用于测试值是否相等

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

见:

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

Equals()
执行两个对象的值比较

事实并非如此。值类型上的
object.Equals
的默认行为是使用它们的相等定义来比较每个字段,引用类型的默认行为是比较它们的引用。可以重写它来执行您希望它执行的任何操作。在这方面,它与
=
操作符完全相同

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


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

给代码赋予语义是一种很好的做法。所以,如果引用比较确实是您应该关心的事情,那么在您的类中使用默认行为;否则,应该使用应用程序上下文相关逻辑进行比较。(所有平等成员的行为都是一致的,如
Equals
GetHashCode
和运算符)

请参阅:不是重复的,因为我问的是普遍接受的标准,而不是最快/任何方法。不同的问题。对于引用类型,除非您重写
Equals
,否则它也会执行引用相等。
通常,首先检查两种类型的引用相等,如果它们不匹配,然后检查值相等(如果需要)。
这只是一种优化,对于实际的语义来说并不重要。如果要删除该检查以实际更改该方法的结果,则需要出现严重错误。这意味着当对象与自身进行比较时,值检查需要失败。请注意,如果基于实际值的检查非常快(如果只有一个成员要比较,并且可以快速检查),那么
// 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);