C# Object Comparison – Difference Between ==, Equals(), and ReferenceEquals()
In C#, ==, Equals(), and ReferenceEquals() are used to compare values or objects.
However, they differ in how comparisons are performed, whether they compare values or object references, and whether their behavior can be customized.
1. What is the == operator in C#?
The == operator is used to compare two operands for equality.
Its behavior depends on the data type and whether the operator has been overloaded.
-
For built-in numeric types, it compares values.
-
For most classes without a custom
==operator, it compares object references. -
For strings, it compares text content.
Example 1: Value type comparison
int a = 10;
int b = 10;
Console.WriteLine(a == b); // True
Explanation:
-
acontains the value10. -
bcontains the value10. -
The
==operator compares their values. -
Both values are equal, so it returns
true.
Example 2: Reference type comparison
public class Employee
{
public int Id { get; set; }
}
Usage:
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
Console.WriteLine(emp1 == emp2); // False
Why does it return false?
Although both objects contain the same Id, they are two different objects in memory.
The Employee class does not overload the == operator, so reference equality is used.
Memory representation
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
emp1 emp2
| |
v v
+---------------+ +---------------+
| Employee | | Employee |
| Id = 101 | | Id = 101 |
+---------------+ +---------------+
Object 1 Object 2
emp1 == emp2
Result: False
Reason:
Both variables reference different objects.
Example 3: String comparison
string a = new string("Hello".ToCharArray());
string b = new string("Hello".ToCharArray());
Console.WriteLine(a == b); // True
Why does it return true?
The string class overloads == to compare string content rather than object identity.
Even though a and b are separate string objects, their contents are equal.
Key Points
-
Operator:
==is an equality operator. -
Value Types: Built-in numeric types are compared by value.
-
Reference Types: Classes without overloaded equality generally use reference comparison.
-
Strings: Compare content because
stringoverloads==. -
Customization: Classes and structs can overload
==. -
Null: Can be used to check for null where the operator is applicable, although overloaded operators can have custom behavior.
-
Common Usage: Comparing numbers, strings, and objects with defined equality operators.
2. What is the Equals() method in C#?
The Equals() method is used to determine whether two values or objects are equal.
It is defined in System.Object and can be overridden by derived classes to provide custom value-based comparison.
Example 1: Value type comparison
int a = 10;
int b = 10;
Console.WriteLine(a.Equals(b)); // True
Explanation:
-
acontains10. -
bcontains10. -
Equals()compares the integer values. -
Both are equal, so it returns
true.
Example 2: Reference type comparison
public class Employee
{
public int Id { get; set; }
}
Usage:
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
Console.WriteLine(emp1.Equals(emp2)); // False
Why does it return false?
By default, a normal class inherits Object.Equals(), which uses reference equality.
Even though both objects contain the same data, they are different instances.
Example 3: Overriding Equals()
We can override Equals() to compare objects based on their properties.
public class Employee
{
public int Id { get; set; }
public override bool Equals(object? obj)
{
if (obj is Employee other)
{
return Id == other.Id;
}
return false;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
Usage:
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
Console.WriteLine(emp1.Equals(emp2)); // True
Console.WriteLine(emp1 == emp2); // False
Explanation:
-
emp1andemp2are different objects. -
We override
Equals()to compare theIdproperty. -
Both objects have
Id = 101. -
Therefore,
Equals()returnstrue. -
==still returnsfalsebecause we have not overloaded that operator.
Important: When overriding Equals(), also override GetHashCode() consistently. Objects considered equal must produce the same hash code.
How Equals() works
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
emp1 emp2
| |
v v
+---------------+ +---------------+
| Id = 101 | | Id = 101 |
+---------------+ +---------------+
| |
+----------+----------+
|
v
Equals(emp2)
|
v
Compare Id values
|
v
101 == 101
|
v
True
What is the difference between instance Equals() and object.Equals()?
Instance method:
string? name = null;
// name.Equals("John"); // NullReferenceException
Static method:
string? name = null;
Console.WriteLine(object.Equals(name, null)); // True
The static object.Equals(a, b) method safely handles null references.
Key Points
-
Method:
Equals()is defined inSystem.Object. -
Default Behavior: For ordinary classes, compares references unless overridden.
-
Value Types: Generally compare values using their type-specific equality implementation.
-
Customization: Can be overridden to compare object properties.
-
Strings: Compare text content.
-
Null Safety:
object.Equals(a, b)safely handles null arguments. -
Hash Code: Override
GetHashCode()when overriding equality. -
Common Usage: Comparing objects based on business properties, such as Employee ID or Product Code.
3. What is ReferenceEquals() in C#?
ReferenceEquals() is a static method of the object class.
It determines whether two references point to the exact same object in memory.
Unlike == and Equals(), its behavior cannot be overridden or overloaded.
Example
public class Employee
{
public int Id { get; set; }
}
Usage:
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = emp1;
Employee emp3 = new Employee { Id = 101 };
Console.WriteLine(
object.ReferenceEquals(emp1, emp2)); // True
Console.WriteLine(
object.ReferenceEquals(emp1, emp3)); // False
Explanation
-
emp1references anEmployeeobject. -
emp2 = emp1copies the reference. -
Therefore,
emp1andemp2point to the same object. -
emp3references a separately created object. -
Even though
emp3.Idis also101, it is a different object.
Memory representation
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = emp1;
Employee emp3 = new Employee { Id = 101 };
emp1 emp2 emp3
| | |
+------+-----+ |
| |
v v
+---------------+ +---------------+
| Employee | | Employee |
| Id = 101 | | Id = 101 |
+---------------+ +---------------+
Object 1 Object 2
ReferenceEquals(emp1, emp2) = True
ReferenceEquals(emp1, emp3) = False
What happens with value types?
int a = 10;
int b = 10;
Console.WriteLine(
object.ReferenceEquals(a, b)); // False
Why?
Value types such as int are boxed when passed to ReferenceEquals().
Each argument is boxed into a separate object, so the references are different.
Key Points
-
Reference Comparison: Checks whether two references identify the same object.
-
Static Method: Called using
object.ReferenceEquals(). -
Cannot Override: Its behavior cannot be customized.
-
Same Object: Returns
true. -
Different Objects: Returns
false, even if their values are equal. -
Value Types: Boxing usually results in separate objects, so direct value-type arguments return
false. -
Null: Returns
trueif both arguments are null. -
Common Usage: Checking object identity and determining whether two references refer to the same instance.
4. Difference Between ==, Equals(), and ReferenceEquals()
|
Feature |
|
|
|
|---|---|---|---|
|
Type |
Operator |
Method |
Static method |
|
Comparison |
Value or reference |
Value or reference |
Reference only |
|
Default class behavior |
Reference comparison |
Reference comparison |
Reference comparison |
|
Value type comparison |
Usually value |
Usually value |
Object identity after boxing |
|
String comparison |
Content |
Content |
Object identity |
|
Can customize |
Yes, overload |
Yes, override |
No |
|
Can compare null |
Yes, where supported |
Static form is null-safe |
Yes |
|
Main purpose |
General equality |
Logical/value equality |
Object identity |
5. Complete Example – All Three Together
public class Employee
{
public int Id { get; set; }
public override bool Equals(object? obj)
{
return obj is Employee other &&
Id == other.Id;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
Usage:
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
Employee emp3 = emp1;
// == Operator
Console.WriteLine(emp1 == emp2); // False
Console.WriteLine(emp1 == emp3); // True
// Equals() Method
Console.WriteLine(emp1.Equals(emp2)); // True
Console.WriteLine(emp1.Equals(emp3)); // True
// ReferenceEquals() Method
Console.WriteLine(
object.ReferenceEquals(emp1, emp2)); // False
Console.WriteLine(
object.ReferenceEquals(emp1, emp3)); // True
Execution flow
Compare Two Objects
|
+-----------+-----------+
| | |
v v v
== Equals() ReferenceEquals()
| | |
v v v
Operator Equality Object
Behavior Method Identity
| | |
v v v
Can Overload Can Override Cannot Override
| | |
v v v
Value or Value or Same Object
Reference Reference Reference?
6. Important Interview Scenarios
Scenario 1: Comparing two integers
int a = 100;
int b = 100;
Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True
Console.WriteLine(object.ReferenceEquals(a, b)); // False
Reason: == and Equals() compare integer values, while ReferenceEquals() checks boxed object identity.
Scenario 2: Comparing two strings
string a = new string("Hello".ToCharArray());
string b = new string("Hello".ToCharArray());
Console.WriteLine(a == b); // True
Console.WriteLine(a.Equals(b)); // True
Console.WriteLine(object.ReferenceEquals(a, b)); // False
Reason: Both strings contain the same text but are different objects.
Scenario 3: Comparing objects using Employee ID
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = new Employee { Id = 101 };
Console.WriteLine(emp1.Equals(emp2)); // True
Reason: The overridden Equals() method compares the Id property instead of object identity.
Scenario 4: Checking whether two variables reference the same object
Employee emp1 = new Employee { Id = 101 };
Employee emp2 = emp1;
bool isSameObject =
object.ReferenceEquals(emp1, emp2);
Console.WriteLine(isSameObject); // True
Reason: Both variables reference the same instance.
7. Important Interview Follow-up Questions
Q1. Does == always compare references for classes?
No. Classes can overload == to compare values. For example, string compares content.
Q2. Does Equals() always compare values?
No. For ordinary classes without an override, Object.Equals() uses reference equality.
Q3. Can we override ReferenceEquals()?
No. It is a static method whose behavior cannot be customized.
Q4. Why does ReferenceEquals() return false for two integers?
Because integers are boxed into separate objects when passed as arguments.
Q5. What is the difference between string.Equals() and ReferenceEquals()?
string.Equals() compares text content, whereas ReferenceEquals() checks whether both references point to the same string object.
Q6. What happens if we override Equals() but not GetHashCode()?
It violates the equality/hash-code contract and can cause incorrect behavior in hash-based collections such as Dictionary and HashSet.
Q7. Which should we use to compare two business objects?
Use Equals() with a properly implemented equality definition, or use an equality comparer, when logical equality is based on business properties.
Quick Interview Revision
|
Method |
Remember |
|---|---|
|
|
Operator-based equality |
|
|
Logical equality; can be overridden |
|
|
Checks exact object identity |
|
|
Compares values |
|
|
Compares content |
|
|
Usually compares references |
|
|
Can compare selected properties |
|
|
Cannot be overridden |
|
|
Must be consistent with |
Interview Answer:
== is an equality operator whose behavior depends on the type and operator overloading. Equals() is a method that can be overridden to provide logical or value-based equality. ReferenceEquals() is a static method that checks whether two references point to exactly the same object. For ordinary classes, == and the default Equals() compare references, while overridden equality methods can compare object properties.