Introduction
When C# 9 was introduced, one of the main features was a new type called Records. These were like classes that were reference based but allowed direct comparison between them and would be considered equal if the members had same values. These are preferably immutable in nature. Then with C# 10 came struct-based records which were value-based with the same properties. Today, we will use both of these in a general context and see the performance difference between them.
Creating the solution and adding the code
Let us create a C# console application in Visual Studio 2022 Community edition. We will then add some simple code to create and populate a record and struct record and then we will compare the performance using the Benchmark library.
After the solution is created, add the below Nugget package.
After this is complete, add the below code to the “Program.cs” file.
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
BenchmarkRunner.Run < RecordsTest > ();
public class RecordsTest {
[Benchmark]
public void RecordStandard() {
var recStandardOne = new LocationA {
PointA = 100.0, PointB = 200.0
};
var recStandardTwo = new LocationA {
PointA = 100.0, PointB = 200.0
};
var recStandardThree = new LocationA {
PointA = 100.0, PointB = 201.0
};
var OneTwo = (recStandardOne.Equals(recStandardTwo)) ? "One and two are equal" : "One and two are not equal";
var OneThree = (recStandardOne.Equals(recStandardThree)) ? "One and three are equal" : "One and three are not equal";
var OneTwoE = (recStandardOne == recStandardTwo) ? "One and two are equal" : "One and two are not equal";
var OneThreeE = (recStandardOne == recStandardThree) ? "One and three are equal" : "One and three are not equal";
Console.WriteLine(OneTwo);
Console.WriteLine(OneThree);
Console.WriteLine(OneTwoE);
Console.WriteLine(OneThreeE);
}
[Benchmark]
public void RecordStuct() {
var recStandardOne = new LocationB {
PointA = 100.0, PointB = 200.0
};
var recStandardTwo = new LocationB {
PointA = 100.0, PointB = 200.0
};
var recStandardThree = new LocationB {
PointA = 100.0, PointB = 201.0
};
var OneTwo = (recStandardOne.Equals(recStandardTwo)) ? "One and two are equal" : "One and two are not equal";
var OneThree = (recStandardOne.Equals(recStandardThree)) ? "One and three are equal" : "One and three are not equal";
var OneTwoE = (recStandardOne == recStandardTwo) ? "One and two are equal" : "One and two are not equal";
var OneThreeE = (recStandardOne == recStandardThree) ? "One and three are equal" : "One and three are not equal";
Console.WriteLine(OneTwo);
Console.WriteLine(OneThree);
Console.WriteLine(OneTwoE);
Console.WriteLine(OneThreeE);
}
}
public record LocationA {
public double PointA {
get;
init;
}
public double PointB {
get;
init;
}
}
public record struct LocationB {
public double PointA {
get;
init;
}
public double PointB {
get;
init;
}
}
Compile in Release mode and run without debugging. After the process is complete you will see the below output,
Hence, we see that in this very simple scenario the performance of the struct record is better than the normal record. This should improve even more with more complex situations.
Summary
In this article, we looked at creating, populating, and comparing values using both records and struct records. We compared the performance using the Benchmark library. We noticed that the performance of the struct records is slightly better than the simple class records. This was a simple scenario. As the situations and code become more complex this will further hold true and struct records will perform better. Hence, it is recommended to use struct records whenever possible.