Comparing Records, Structs, and Classes in C#: When to Use What?
C# provides a few ways to define types—records, structures, and classes. Each has its own qualities and limitations. In this blog post, I will discuss each construct and help you identify which one to use in your project.
What is a class in C#?
A class defines reference types, which means that when a class instance is created, a reference to that object is made, and the reference is passed around rather than the object itself. A class can also be seen as a blueprint or user-defined type that follows object-oriented principles (OOP) by encapsulating and abstracting fields and behaviors.
A class contains data members in the form of properties or fields to store values. It also has methods, sometimes referred to as behaviors, for performing operations.
What is a struct in C#?
Structs are value types, meaning that when a struct instance is created, a copy of that instance is created and passed around, unlike classes, which pass the actual reference. Struct offers a lightweight solution by eliminating the overhead required to hold referencing.
Structs can also contain data members and methods, just like classes.
What is a record in C#?
Records are immutable types introduced in C# 9.0. They offer type declarations with simple and concise syntax. Records are reference types, just like classes. However, Like structs, they have built-in functionality for comparing and hashing objects. Records can contain data members and members just like the other two counterparts.
Differences in usage and functionalities
Although class, struct, and records are type declarations, each assists you in specific scenarios. Let's dive deeper into each
Class
Classes are the most complex and feature-enrich type. They fulfill OOP concepts and offer parameterized and parameterless constructors. You can leverage reference type creation and mutability in class objects. Besides you can make properties and fields immutable with read-only or init.
Code example
public class Student
{
public string Name { get; }
public int Semester { get; set; }
public Student(string name, int semester)
{
Name = name;
Semester = semester;
}
public void Greetings()
{
Console.WriteLine($"Hi, my name is {Name}.");
}
}
// Usage
var s1 = new Student("Morgan", 4);
var s2 = s1;
s2.Semester= 6;
Console.WriteLine(s1.Semester);
Console.WriteLine(s2.Semester);
Output
In the example, we set the value of s2.Semester
to 6
. However, the new value was also set to s1.Semester
since s2
is a reference to s1
.
Data members can be made immutable with init
:
public class Student
{
public string Name { get; init; }
...
and with readonly
:
public class Student
{
Public readonly string Name;
public Student(string name)
{
Name = name;
}
...
Both the implementation and usage of init
and readonly
are different, but I will not expand further in this blog post.
Usage of class
Classes are ideal for modeling complex data objects and implementations of methods. This is enabled because classes leverage OOP principals completely and because data members can be modified. The only limitation is that classes keep an overhead to holding reference of copied instances.
Struct
Structs are simple mutable types that use value-based modification. However, it does not support the inheritance known from OOP and is declared sealed by default. Neither are parameterless constructors supported.
Code example
public struct Point
{
public double X { get; set; }
public double Y { get; set; }
public Point(double x, double y)
{
X = x;
Y = y;
}
public void Print()
{
Console.WriteLine($"X {X} , Y {Y}");
}
}
// Usage
var p1 = new Point(3.2, 5.6);
var p2 = p1;
p2.Y= 6;
p1.Print();
p2.Print();
Output
As seen in the output, setting the value of p2.Y
to 6
only modifies p2
and not p1
.
Usage of struct
Struct is ideal when you want to declare simple lightweight data structures. Just like the above example required type for a point, so you can define it struct by eliminating additional reference overhead. In other words, when your type needs to value base comparison and storage, a struct can help you reduce additional storage.
Record
Records hold many of the benefits from both classes and structs. They are reference types like classes and are compared by value just like structs. Records support inheritance, however its instances are immutable so we cannot change the value of the parents.
Code example
public record Student(string Name, int Age)
{
// Method to display a formatted string
public string GetDetails()
{
return $"Student: {Name}, Age: {Age}";
}
}
// Notice that data members are declared concisely within a line
// Usage
var s1 = new Student("Alex", 25);
Console.WriteLine(s1.GetDetails());
You can simply use the records' default ToString()
method to print all public properties:
Console.WriteLine(s1.ToString());
Usage of records
Records came into play when you need type for value-based comparison and equality such as DTOs or other data-centric designs. Your code looks clean and concise as you don't need boilerplate code for type declaration in C# records.
Conclusion
C# provides different ways to declare types. We explored each of them in detail and found which one is suitable for what scenarios. Classes are the most common and complex laced with OOP principles. They support reference-based modification and declare mutable objects. Structs are another option in C#, that are value-types. They are also mutable and lightweight which reduces the cost of referencing overhead. Finally, records were discussed which are immutable reference types, and perform value-based comparisons. Each of them has its own feature for what they are introduced in the C# ecosystem.
elmah.io: Error logging and Uptime Monitoring for your web apps
This blog post is brought to you by elmah.io. elmah.io is error logging, uptime monitoring, deployment tracking, and service heartbeats for your .NET and JavaScript applications. Stop relying on your users to notify you when something is wrong or dig through hundreds of megabytes of log files spread across servers. With elmah.io, we store all of your log messages, notify you through popular channels like email, Slack, and Microsoft Teams, and help you fix errors fast.
See how we can help you monitor your website for crashes Monitor your website