Value vs Link

What decision should I make regarding Equals (), ReferenceEquals () and == from the following results? What are they actually producing?

#region
int integer = 1;
int integer2 = integer;

bool referenceEquality = (integer == integer2);//true
bool valueEquality = integer.Equals(integer2);//true
bool valueEqualityMore = object.Equals(integer, integer2);//true
bool valueEqualityMoreMore = object.ReferenceEquals(integer, integer2);//false
#endregion

#region
int integer = 1;
int integer2 = 1;

bool referenceEquality = (integer == integer2);//true
bool valueEquality = integer.Equals(integer2);//true
bool valueEqualityMore = object.Equals(integer, integer2);//true
bool valueEqualityMoreMore = object.ReferenceEquals(integer, integer2);//false
#endregion

#region
MyClass obj = new MyClass(1, "Hello");
MyClass obj2 = obj;

bool referenceEquality = (obj == obj2);//true
bool valueEquality = obj.Equals(obj2);//true
bool valueEqualityMore = object.Equals(obj, obj2);//true
bool valueEqualityMoreMore = object.ReferenceEquals(obj, obj2);//true            
#endregion

#region
MyClass obj = new MyClass(1, "Hello");
MyClass obj2 = new MyClass(1, "Hello");

bool referenceEquality = (obj == obj2);//false
bool valueEquality = obj.Equals(obj2);//false
bool valueEqualityMore = object.Equals(obj, obj2);//false
bool valueEqualityMoreMore = object.ReferenceEquals(obj, obj2);//false
#endregion

      

Hell! I do not understand anything.

To me, the Equals () link of the 1st block should return true. == should return false in the second block (since the links are different). And, both of Equals () in the 4th block should return true (since their values ​​are the same).

+2


source to share


5 answers


The first point of confusion you seem to run into is that with values ​​of types, i.e. int

, float

, DateTime

, The operator ==

is equality values. With reference types ==

(see below for default) reference equality. This explains the inconsistency of the answers in your first two whole cases.

Second, the default implementation Equals()

checks for reference equality, not equality equality. Therefore, since it seems that MyClass

does not override Equals()

, which explains the inconsistency of answers between your reference cases.

In addition, many reference types, such as String

, override the operator ==

to provide value equality semantics. So do your best until you remember what types are there to find the documentation.



In short:

  • Value types
    • ==

      is equality of values ​​(for frame types)
    • Not a reference type, so reference equality is meaningless
  • Link types
    • ReferenceEquals()

      is always referential equality
    • ==

      defaults to referential equality, but can (and often for framework types) be overridden to provide equality by value
    • Equals()

      is reference equality by default, but can (and often for frame types) be overridden to provide equality by value
+8


source


ReferenceEquals

:
two objects are the same if they point to the same location in memory. This does not apply to two different types of values.

Equals

:
two objects are equal if Equals override thinks they are equal. This usually means if ReferenceEqual returns true and if properties return true. Equals

behaves differently in relation to an object or structure. Note: each built-in value type (int, double, IntPtr) has overridden Equals

, so it behaves differently for value types (compares content), then with ReferenceEquals

(compares addresses).

==

:
Returns true if two objects have equal references or if the two value types have the same content. Boxed socket types are unpacked before they are mapped, and they do not map directly to an object.



Note that yours new MyClass(...)

returned false with Equals

. This is because the implementation MyClass

does not override the method Equals

. Result: it behaves the same as ReferenceEquals

.

Update: Added note to Equals

for value types

+1


source


ReferenceEquals

checks if a reference to one object refers to one object. That is, they point to the same place in memory.

Equals

is a virtual method, so in practice it can be overridden to do something. However, the purpose of the method is to compare instances in a way that makes sense for the type, whatever it is. If Equals

not overridden, an implementation object.Equals

that is equivalent is used ReferenceEquals

.

==

is an equality operator that, by default, compares reference equality for instances of reference types (i.e., classes, boxed types, interfaces) and value equality (same values ​​for fields) for instances of value types (i.e. structures). ==

can be overloaded to provide custom behavior, but it's not virtual like Equals

.

Using int

as object

, for example, passing it to a method, for example ReferenceEquals

, which has parameters object

, pushes int

, creating an object on the heap with an integer inside. object.ReferenceEquals(integer1, integer2)

basically means object.ReferenceEquals((object)integer1, (object)integer2)

.

Comparing different plug-in instances of the same integer by referential equality ( ReferenceEquals

or ==

) will give false

, and an equality value ( Equals

) will give true

. For unboxed same integers that are value types ==

and Equals

both compare the equality value and thus give true

.

+1


source


The default operator==

behaves like this when used as a==b

. Note that it operator==

can be overridden to do anything.

  • If a

    is a value type, then it compiles as a.Equals(b)

    .
  • If a

    is a reference type, then it compiles as object.Equals(a,b)

    .

object.Equals(a, b)

works only on reference types and does the following:

  • If a

    - null

    , return(b==null)

  • Otherwise, call a.Equals(b)

object.ReferenceEquals(a, b)

only works on reference types. An object reference in C # /. NET is internally held as a pointer. This method returns true if the references a

and are the b

same, that is, if they point internally to the same object.

Value types come in two forms: unboxed and boxed. In the following cases discussing value types, I will use the following variables:

int unboxed = 3;
// boxing occurs automatically when a value type is cast to object or
// to an interface. This allocates memory on the heap to store the value
// and places a reference (internally a pointer) to this memory in boxed.
object boxed = unboxed;

      

At this point, it boxed

behaves like a reference type. Two values ​​in the box may not be in the same place in memory, as you can see in your call to object.ReferenceEquals(integer1, integer2)

(automatic boxing occurs due to the casting of each parameter in object

). When you call object.Equals(integer1, integer2)

, the values ​​are inserted into the square, but since the nested form is integer1

not null, the call behaves like integer1.Equals((object)integer2)

, which returns true

because the nested values ​​are like 1

. (see note below why I have a manual feed here).

Note on the above tutorial:, System.Int32

along with most other value types, has a method Int32.Equals(Int32 other)

, so a call integer1.Equals(integer2)

will not put a value integer2

. This has a large (positive) performance impact for lightweight value types.

+1


source


I amended what the actual comparisons did. I added the same comparisons for all cases, since you were only doing .Equals (int) for an integer (which uses the == operator) and not .Equals (object) as for other types. I've also added explicit castings for parameters to show which implicit castings are caused by using them as parameters:

int integer = 1;
int integer2 = 1; // exactly the same result as copying integer

bool valueEquality = (integer == integer2); //true
bool valueEquality2 = integer.Equals(integer2); //true
bool typeAndValueEquality = integer.Equals((object)integer2); //true
bool typeAndValueEquality2 = object.Equals((object)integer, (object)integer2); //true
bool referenceEquality = object.ReferenceEquals((object)integer, (object)integer2); //false

//

MyClass obj = new MyClass(1, "Hello");
MyClass obj2 = obj;

bool referenceEquality = (obj == obj2); //true
bool referenceEquality2 = obj.Equals((object)obj2); //true
bool typeAndReferenceEquality = object.Equals((object)obj, (object)obj2); //true
bool referenceEquality3 = object.ReferenceEquals((object)obj, (object)obj2); //true

//

MyClass obj = new MyClass(1, "Hello");
MyClass obj2 = new MyClass(1, "Hello");

bool referenceEquality = (obj == obj2); //false
bool referenceEquality2 = obj.Equals((object)obj2); //false
bool typeAndReferenceEquality = object.Equals((object)obj, (object)obj2); //false
bool referenceEquality = object.ReferenceEquals((object)obj, (object)obj2); //false

      

+1


source







All Articles