PROGRAMMING

Is record a new class in C#?

record vs. class

Shiljo Paulson
4 min readNov 20, 2021
Photo by Steve Harvey on Unsplash

Humans evolve so does language.

In c# version 9.0 it introduced a new feature called record which is of reference type & with the version 10 the type can be made as a value type as well.

So, what’s the big fuzz about record? in one of my previous posts, I mentioned about Various ways to Compare two c# objects while unit testing in case if you have not read it, please read.

The main use case record solve is comparison of two objects of same type is now easy which was previously we must explicitly write equality (Equals method) code for it now with the introduction of record we don’t have to instead complier does the hard work for us.

Let's see an example

class Program
{
static void Main(string[] args)
{
var employee1 = new Employee { Id = 1000, FirstName = "Shiljo" };
var employee2 = new Employee { Id = 1000, FirstName = "Shiljo" };

Console.WriteLine(employee1.Equals(employee2));//True
Console.WriteLine(employee1 == employee2);//True
}
}

public record Employee
{
public int Id { get; set; }

public string FirstName { get; set; }
}

In the above code if you notice I have added record instead of class here both the equality and Equals() method does return True whereas if the same was class then it will return False.

In case, if you want to make class perform the same then you might end up writing something like below

class Program
{
static void Main(string[] args)
{
var employee1 = new Employee { Id = 1000, FirstName = "Shiljo" };
var employee2 = new Employee { Id = 1000, FirstName = "Shiljo" };

Console.WriteLine(employee1.Equals(employee2));//True
Console.WriteLine(employee1 == employee2);//True
}
}

public class Employee
{
public int Id { get; set; }

public string FirstName { get; set; }

public override bool Equals(object obj)
{
if (obj == null) { return false; }
if (object.ReferenceEquals(this, obj)) { return true; }

var employee = obj as Employee;
return this.Id == employee.Id
&& this.FirstName == employee.FirstName;
}

public override int GetHashCode()
{
return $"{this.Id}{this.FirstName}".GetHashCode();
}

public static bool operator ==(Employee left, Employee right)
{
if ((object)left == null)
return (object)right == null;

return left.Equals(right);
}

public static bool operator !=(Employee left, Employee right)
{
return !(left == right);
}
}

The above is the equivalent implementation using class. Here, I must introduce four methods like Equals, GetHashCode, operators ==and != which is time consuming this is exact same thing is what is done in record as well, but compiler does it for you.

What else `record` does?

The behavior of ToString()method is better compared to class.

Let's see the example

class Program
{
static void Main(string[] args)
{
var employee = new Employee { Id = 1000, FirstName = "Shiljo" };

Console.WriteLine(employee.ToString());//Employee { Id = 1000, FirstName = Shiljo }
}
}

public record Employee
{
public int Id { get; set; }

public string FirstName { get; set; }
}

With record it has become more useful and here is the output for ToString() method

Employee { Id = 1000, FirstName = Shiljo }

whereas if you do the same with class you will end up getting like the below which basically returns the Class\Type Name.

Employee

So, can we Override ToString() in record?

Yes, we can override just like how we did with class but here we have one additional also methodPrintMembers() which can be overridden.

Let's see how the compiler would have written the equivalent code for us.

public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Employee");
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(" ");
}
stringBuilder.Append("}");
return stringBuilder.ToString();
}

protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"Id = {Id}");
stringBuilder.Append($", FirstName = {FirstName}");
return true;
}

If you see the above code, we can restrict members of the class getting printed by returning false in case if we want.

Inheritance and override PrintMembers

class Program
{
static void Main(string[] args)
{
var employee = new Employee { Id = 1000, FirstName = "Shiljo", DepartmentId = 100 };

Console.WriteLine(employee.ToString());//Employee { Id = 1000, FirstName = Shiljo, DepartmentId = 100 }
}
}

public record Person
{
public int Id { get; set; }

public string FirstName { get; set; }
}

public record Employee : Person
{
public long DepartmentId { get; set; }

protected override bool PrintMembers(StringBuilder stringBuilder)
{
base.PrintMembers(stringBuilder);
stringBuilder.Append($", DepartmentId = {DepartmentId}");
return true;
}
}

Here if you notice I have inherited Employee record from Person record and I am also overriding PrintMembers() method and now ToString() will return

Employee { Id = 1000, FirstName = Shiljo, DepartmentId = 100 }

Few things which I tried are record cannot inherit from a class

Summary

  • With record no code for comparison.
  • The ToString() is finally handy and returning something sensible.
  • Can override ToString() , Equals() and operator overloading == & !=
  • No code for comparison while writing unit tests.
  • The record can be inherited just like class but cannot be inherited from a class and possible to inherit from interface.

The record is ideal choice if you want things to be compared.

Let me know your valuable comments and do enjoy coding.

--

--

Shiljo Paulson
Shiljo Paulson

Written by Shiljo Paulson

System Design, Full stack Developer, good at OOPs, .Net, C#, TypeScript, JavaScript, SQL, HTML. Recent times interest is on Cloud, System Design and GoLang.

No responses yet