While trying to implement a simple singly linked list in C#, I noticed that ==
does not work while comparing two object type variables boxed with an int value but .Equals
works.
Wanted to check why that is so.
The below snippet is a generic object type Data property
public class Node {
/// <summary>
/// Data contained in the node
/// </summary>
private object Data { get; set; };
}
The below code traverses the singly linked list and searches for a value of type object -
/// <summary>
/// <param name="d">Data to be searched in all the nodes of a singly linked list
/// Traverses through each node of a singly linked list and searches for an element
/// <returns>Node if the searched element exists else null </returns>
public Node Search(object d)
{
Node temp = head;
while (temp != null)
{
if (temp.Data.Equals(d))
{
return temp;
}
temp = temp.Next;
}
return null;
}
However, if I replace
temp.Data.Equals(d)
with temp.Data == d
it stops working even though temp.Data
and d
both have the value '3'. Any reasons why ==
does not work on object type variables?
Here's the snippet from the Main function -
SinglyLinkedList list = new SinglyLinkedList();
list.Insert(1);
list.Insert(2);
list.Insert(3);
list.Insert(4);
list.Insert(5);
list.Print();
Node mid = list.Search(3);
I believe since I am passing an int value 3
and the Search method expects an object type, it would have successfully boxed 3 as a object type. However, not sure why ==
doesn't work but .Equals
does.
Is ==
operator overloaded for value types only?
There are two reasons:
Equals
is not bounded with==
and vice versa, and by default checks for reference-equality:As you can read in the specifications of
.Equals
vs==
:Although the compiler will throw an error if you do not override the
!=
as well, and will warn that you better override both.Equals
and.GetHashCode
.So overriding/overloading the
.Equals
,==
and!=
are different things. Overriding.Equals
has no effect on overloading==
and!=
. After all the==
is a custom operator. Although it is not wise to do so, you could use it for another purpose than an equality check.Furthermore operators are resolved at compile-time:
Take the following example the following
csharp
interactive shell program:As you can see,
==
gives a different result if you call the objects asobject
, or asFoo
. Since you use anobject
, the only binding at compile time C# can make is the one with reference equality.It's because the
System.Object
implementation of==
tests reference equality, like the staticEquals(object, object)
, while instanceEquals(object)
is overloaded, so it checks the actual value.When you box a value type twice, you get two different instances, so of course reference equality fails.
The operator, being static, is bound at compile time, so there is no dynamic dispatch. Even with strings, which are already reference types and are therefore not boxed when assigned to an object-type variable, you can get an unintended reference comparison with the == operator if one of the operands has a static type other than
string
.The operator
==
is like an overloaded static function selected based on the compile time types. In your case the type of the values isObject
, for which the==
operator implements reference equality.On the other hand
.Equals
is virtual and overridden, so it will do the comparison based on the actual types.