swirl
Home Software Blog Wallpapers Webtools
Correct way to think of objects, their identity and equality.
Sunday 06, August 2017   |   Post link   |   Sample code  Download related material

Typically we don't really pay much attention to objects when writing our applications. For e.g. if we are designing a school system where student objects are going to used, we typically define our Student class as:

class Student
{
	public int Grade { get; set; }
	public int Roll { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
}

Now lets say somewhere in the application a list of student objects are stored:

List<Student> students = new List<Student>();
students.Add(new Student { Roll = 1, Grade = 1, FirstName = "Neel", LastName = "Barman" });
students.Add(new Student { Roll = 2, Grade = 1, FirstName = "Arjun", LastName = "Ramesh" });

Student neel = new Student { Roll = 1, Grade = 1, FirstName = "Neel", LastName = "Barman" };
Console.Write("Is Neel in the list? {0}\r\n", students.Contains(neel));

So what's the answer to the above question? It is False when clearly it should have been true.

One way to get around is to explicitly check the business condition that if a student has the same roll-number in the same grade, the student must be the same.

Console.Write("Is Neel in the list? {0}\r\n",
				students.Where((s) => s.Roll == neel.Roll && s.Grade == neel.Grade).Count() == 1
			);

Yes, this works but something really bad has happened. The business logic for determining if the student is the same has now crept outside, this means every single place where such a comparison has to be made the code must be aware of this rule.

So how do we fix it? Answer is simple, we need to override the Equals(object obj) method of System.Object. Another thing to remember is that when one overrides the Equals method .NET recommends we override the GetHashCode() method too. Here is the improved code:

class Student
{
	public int Grade { get; set; }
	public int Roll { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }

	public override bool Equals(object obj)
	{
		if (obj == null) return false;
		if (obj.GetType() != GetType()) return false;
		Student other = (Student)obj;
		return Grade == other.Grade && Roll == other.Roll;
	}

	public override int GetHashCode()
	{
		return Roll ^ Grade;
	}
}

If we now run the code to test if the object exists in the list, we get True in both cases. What if we now test our objects ourselves students[0] == neel?

Console.WriteLine("Do we have the same student? [{0}]", students[0] == neel);

The answer is False! It should be true. You guessed it, checking via == isn't using the Equals() implementation. To get this working we need to provide custom implementation for == operator.

public static bool operator == (Student lhs, Student rhs)
{
	return lhs.Equals(rhs);
}

public static bool operator !=(Student lhs, Student rhs)
{
	return !lhs.Equals(rhs);
}

As you see we have implemented both == as well as != operator because if you override one, you need to override the other also. Ok, now after all this what if we still want to check if student[0] and neel point to the same object? For that we have the Object.ReferenceEquals() method - this method works by comparing the memory addresses of the actual objects; clearly student[0] and neel are two different objects and therefore the code below correctly prints False.

Console.WriteLine("Do we have the same object? [{0}]", object.ReferenceEquals(students[0], neel));
Sample code  Download related material

Categories: C# (3) Programming (28)

Comments

Posts By Year

2024 (4)
2023 (5)
2022 (10)
2021 (5)
2020 (12)
2019 (6)
2018 (8)
2017 (11)
2016 (6)
2015 (17)
2014 (2)
2013 (4)
2012 (2)

Posts By Category

.NET (4)
.NET Core (2)
ASP.NET MVC (4)
AWS (5)
AWS API Gateway (1)
Android (1)
Apache Camel (1)
Architecture (1)
Audio (1)
Azure (2)
Book review (3)
Business (1)
C# (3)
C++ (2)
CloudHSM (1)
Containers (4)
Corporate culture (1)
Database (3)
Database migration (1)
Desktop (1)
Docker (1)
DotNet (3)
DotNet Core (2)
ElasticSearch (1)
Entity Framework (3)
Git (3)
IIS (1)
JDBC (1)
Java (10)
Kibana (1)
Kubernetes (1)
Lambda (1)
Learning (1)
Life (7)
Linux (2)
Lucene (1)
Multi-threading (1)
Music (1)
OData (1)
Office (1)
PHP (1)
Photography (1)
PowerShell (2)
Programming (28)
Python (1)
Rants (5)
SQL (2)
SQL Server (1)
Security (3)
Software (1)
Software Engineering (1)
Software development (2)
Solr (1)
Sql Server (2)
Storage (1)
T-SQL (1)
TDD (1)
TSQL (5)
Tablet (1)
Technology (1)
Test Driven (1)
Testing (1)
Tomcat (1)
Unit Testing (1)
Unit Tests (1)
Utilities (3)
VC++ (1)
VMWare (1)
VSCode (1)
Visual Studio (2)
Wallpapers (1)
Web API (2)
Win32 (1)
Windows (9)
XML (2)

Posts By Tags

.NET(6) API Gateway(1) ASP.NET(4) AWS(3) Adults(1) Advertising(1) Android(1) Anti-forgery(1) Asynch(1) Authentication(2) Azure(2) Backup(1) Beliefs(1) BlockingQueue(1) Book review(2) Books(1) Busy(1) C#(4) C++(3) CLR(1) CORS(1) CSRF(1) CTE(1) Callbacks(1) Camel(1) Certificates(1) Checkbox(1) Client authentication(1) CloudHSM(1) Cmdlet(1) Company culture(1) Complexity(1) Consumer(1) Consumerism(1) Containers(3) Core(2) Custom(2) DPI(1) Data-time(1) Database(4) Debugging(1) Delegates(1) Developer(2) Dockers(2) DotNetCore(3) EF 1.0(1) Earphones(1) Elastic Search(2) ElasticSearch(1) Encrypted(1) Entity framework(1) Events(1) File copy(1) File history(1) Font(1) Git(2) HierarchyID(1) Hyper-V(1) IIS(1) Installing(1) Intelli J(1) JDBC(1) JSON(1) JUnit(1) JWT(1) Java(3) JavaScript(1) Kubernetes(1) Life(1) LinkedIn(1) Linux(2) Localization(1) Log4J(1) Log4J2(1) Logging(1) Lucene(1) MVC(4) Management(2) Migration history(1) Mirror(1) Mobile Apps(1) Modern Life(1) Money(1) Music(1) NGINX(1) NTFS(1) NUnit(2) OData(1) OPENXML(1) Objects(1) Office(1) OpenCover(1) Organization(1) PHP(1) Paths(1) PowerShell(2) Processes(1) Producer(1) Programming(2) Python(2) QAAC(1) Quality(1) REDIS(2) REST(1) Runtimes(1) S3-Select(1) SD card(1) SLF4J(1) SQL(2) SQL Code-first Migration(1) SSH(2) SSL(1) Sattelite assemblies(1) School(1) Secrets Manager(1) Self reliance(1) Service(1) Shell(1) Solr(1) Sony VAIO(1) Spirituality(1) Spring(1) Sql Express(1) System Image(1) TDD(1) TSQL(3) Table variables(1) Tables(1) Tablet(1) Ubuntu(1) Url rewrite(1) VMWare(1) VSCode(1) Validation(2) VeraCode(1) Wallpaper(1) Wallpapers(1) Web Development(4) Windows(2) Windows 10(2) Windows 2016(2) Windows 8.1(1) Work culture(1) XML(1) Yii(1) iTunes(1) open file handles(1) renew(1) security(1) static ip address(1) ulimit(1)