PROGRAMMING
Is record a new class in C#?
record vs. class
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 likeclass
but cannot be inherited from aclass
and possible to inherit frominterface
.
The record
is ideal choice if you want things to be compared.
Let me know your valuable comments and do enjoy coding.