简体   繁体   English

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

[英]C# operator== : what is standard practice (reference/value equality)?

Explanation: 说明:

  • Equals() compares the values of two objects. Equals()比较两个对象的值。
  • ReferenceEquals() compares their references. ReferenceEquals()比较它们的引用。

For reference types operator== by default compares references, while for value types it performs (AFAIK) the equivalent of Equals() using reflection. 对于引用类型, operator==默认情况下会比较引用,而对于值类型,它将执行(AFAIK)使用反射的Equals()等效项。

So. 所以。 I have a situation where I need to compare two reference types by their values. 我有一种情况,我需要按它们的值比较两个引用类型。 I can explicitly call Equals() or I can overload operator== to perform the desired comparison. 我可以显式调用Equals() ,也可以重载operator==来执行所需的比较。

However, overloading operator== for value comparison kinda-sorta violates the principle of least astonishment. 但是,对于值比较而言,重载operator==有点违反了最小惊讶原则。 On the other hand explicitly calling two-object Equals looks like overkill. 另一方面,显式调用两个对象的Equals看起来像是过分杀伤。

What is standard practice here? 这里的标准做法是什么?


I know how to override Equals() . 我知道如何重写Equals() The question was whether it is commonly acceptable to override operator== to test for value equality on reference types or whether it is commonly accepted practice to explicitly call Equals/ReferenceEquals to explicitly specify which comparison you want. 问题是,是否可以覆盖operator==来测试引用类型上的相等性,还是普遍接受的做法是显式调用Equals / ReferenceEquals来显式指定所需的比较。

What is standard practice? 什么是标准做法?

The "standard practice" is, if you want to check two elements for equality which isn't reference equality, you need to implement IEquatable<T> , which introduces a Equals(T other) method, and override GetHashCode . “标准做法”是,如果要检查两个元素的相等性(不是引用相等性),则需要实现IEquatable<T> ,它引入了Equals(T other)方法,并重写GetHashCode That way, you control the way these two objects are compared. 这样, 您可以控制比较这两个对象的方式。 Usually, this includes overriding the == and != operators as well. 通常,这还包括覆盖==!=运算符。

while for value types it performs (AFAIK) equivalent of Equals() using reflection. 而对于值类型,它使用反射执行(AFAIK)等效于Equals()。

Only if your value type has a member which is a reference type. 仅当您的值类型具有作为引用类型的成员时。 If it's all value types, it will do a bit comparison of these two objects : 如果都是值类型, 它将对这两个对象进行一些比较

// 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);

The question was whether it is commonly acceptable to override operator== to test for value equality on reference types 问题是,通常是否可以覆盖operator ==来测试引用类型上的值相等性

It really depends on what you're doing. 这实际上取决于您在做什么。 It is encouraged to override the == operator once you override Equals because you want a consistent behavior value equality semantics. 鼓励您在重写Equals重写==运算符,因为您想要一致的行为值相等语义。 This depends on your definition of equality between two objects. 这取决于您对两个对象之间相等性的定义。

Although, If an object is mutable, then doing value comparison might result in odd scenarios where two objects are considered equal but later, one is mutated. 虽然,如果一个对象是可变的,那么进行值比较可能会导致奇怪的情况,其中两个对象被认为是相等的,但后来,一个对象就被突变了。 This should definitely be analyzed on per case basis. 绝对应该根据具体情况对此进行分析。 Usually, overriding Equals should suffice. 通常,重载Equals就足够了。

Equals() performs value comparison of two objects. Equals()执行两个对象的值比较。

This is not true. 这不是真的。 The default behavior of object.Equals on value types is to compare each of the fields using their definition of equality, the default behavior of reference types is to compare their references. object.Equals的默认行为是使用字段的相等性定义比较每个字段,引用类型的默认行为是比较它们的引用。 It can be overridden to do whatever you want it to do. 做任何您想做的事都可以被覆盖。 It is exactly the same as the == operator in this regard. 在这方面,它与==运算符完全相同。

The only difference between the == operator and Equals is that Equals will perform a virtual dispatch on the first (but not the second) operand, finding the implementation of the method based on the runtime type of that object. ==运算符和Equals之间的唯一区别是, Equals将在第一个(但不是第二个)操作数上执行虚拟调度,并根据该对象的运行时类型查找方法的实现。 The == operator is entirely statically bound; ==运算符是完全静态绑定的; it considers only the compile time type of both operands. 它仅考虑两个操作数的编译时类型。 Other than this difference in binding both have the same default behaviors, and both can be overridden to provide whatever implementation you want. 除了绑定方面的差异之外,两者都具有相同的默认行为,并且都可以重写两者以提供所需的任何实现。

The standard practice is to always ensure that the behavior of Equals and operator == is the same for your type. 标准做法是始终确保Equalsoperator ==的行为与您的类型相同。 If you override the Equals method to change the equality semantics, then you should also overload the == operator to provide *identical semantics`, and vice versa. 如果您重写Equals方法来更改相等语义,则还应该重载==运算符以提供* identified语义,反之亦然。

The question was whether it is commonly acceptable to override operator== to test for value equality 问题是,通常是否可以覆盖operator ==来测试值的相等性

It depends on the object, if the object is immutable then you can override == operator, otherwise not. 这取决于对象,如果对象是不可变的,则可以覆盖==运算符,否则不可以。 (Remember they are just guidelines) . (请记住,它们只是准则)

See: Guidelines for Overriding Equals() and Operator == (C# Programming Guide) 请参见: 重写Equals()和运算符==的准则(C#编程指南)

By default, the operator == tests for reference equality by determining whether two references indicate the same object. 默认情况下,运算符==通过确定两个引用是否指示同一对象来测试引用是否相等。 Therefore, reference types do not have to implement operator == in order to gain this functionality. 因此,引用类型不必实现运算符==即可获得此功能。 When a type is immutable , that is, the data that is contained in the instance cannot be changed, overloading operator == to compare value equality instead of reference equality can be useful because, as immutable objects, they can be considered the same as long as they have the same value. 当类型是不可变的时 ,即实例中包含的数据无法更改时, 重载运算符==以比较值相等性而不是引用相等性可能会很有用,因为作为不可变对象,它们可以视为长因为它们具有相同的价值。 It is not a good idea to override operator == in non-immutable types. 在非不可变类型中覆盖运算符==不是一个好主意。

It's a good practice to give a semantic meaning to your code. 赋予代码语义是一个好习惯。 So, if reference comparison is really something you should care about, use default behaviour for your classes; 因此,如果引用比较确实是您应该关心的事情,请对类使用默认行为; otherwise your application context dependent logic should be used for comparison. 否则,应使用与应用程序上下文相关的逻辑进行比较。 (with consistent behaviour of all the equality members like Equals , GetHashCode and operators) (具有所有相等成员(如EqualsGetHashCode和operator)的一致行为)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM