Working with Record Types in C#

C# Programming Guide

You can create immutable objects to ensure thread safety. Once you have created an immutable object, you cannot alter it. This makes an immutable object thread-safe and prevents race conditions. The C# programming language introduced support for immutability with init-only properties and record types recently (in C# 9, to be more precise). This C# programming tutorial discusses record types and how to work with it in C#.

Looking to learn how to program .NET applications in a classroom or course environment? Check out our list of the Top Online Courses to Learn .NET.

What are Record Types in C#?

The introduction of record types in C# 9 was a significant development. Developers can take advantage of record types to build immutable value types. A record type is defined using the record keyword. The record keyword defines record types. A record type is a value type and an immutable type that can not be changed once created.</p>

Records in C# 9 provide a way to create immutable value types. The record keyword defines a record type like enums, structs, and classes. However, unlike these other types of constructs, record types are designed to be immutable by default. When you define a record type with properties and methods, the compiler will ensure those properties can never change after they are created.

Anatomy of Record Types in C#

In C# 9, records are a new type that can replace classes and structs. Record structs are introduced in C# 10, allowing you to define records as value types. The difference between records and classes is that records utilize value-based equality. Records of the same type with similar specifications and similar values in all fields are equal.

In C# 9, a record type is a lightweight, immutable data type (or lightweight class) with primarily read-only properties. A record type is thread-safe, and because it is immutable, you cannot change it after it is created. Note that record types can only be initialized inside constructors.

Instead of using the class or struct keywords, you can specify a record type using the record keyword. If you want to indicate that a record is a reference type, you can specify it as a record class. In contrast to a reference type, records have value-based semantics. To create value-type records, you define a record struct. For your record type, the compiler produces a variety of methods to enforce value semantics.

These include overridable versions of Object.EqualsObject.GetHashCode, and a virtual Equals method that accepts a record type as an argument. It also includes methods for the operators == and !=.

Read: The Best Courses to Learn C# Online

Programming Record types in C#


Refer to the following source code that shows how you can define a record type in C#:

public record Employee
{
   public int Id { get; set; }
   public string FirstName { get; set; }
   public string MiddleName { get; set; }
   public string LastName { get; set; }
   public string Department { get; set; }
   public string Address { get; set; }
   public string Phone { get; set; }
}

Note that the record type we’ve defined is not immutable yet. Since it is not immutable yet, the following source code is perfectly valid:

Employee employee = new Employee();
employee.FirstName = “Joydip”;
employee.MiddleName = “”;
employee.LastName = "Kanjilal";
employee.Department = “Development”;
employee.Address = "Banjara Hills, Hyderabad, Telengana, INDIA";
employee.Phone = "1234567890";

To make the record type immutable, you must use init properties in your record as shown in the source code below:

public record Employee
{
   public int Id { get; init; }
   public string FirstName { get; init; }
   public string MiddleName { get; init; }
   public string LastName { get; init; }
   public string Department { get; init; }
   public string Address { get; init; }
   public string Phone { get; init; }
}

Now if you create an instance of the record and attempt to initialize its members, a compilation error will be generated since your properties are init-only. Note that you can initialize init-only properties inside a constructor only. You can use the following source code to instantiate the record type and initialize its properties:

Employee employee = new Employee()
{
    Id = 1,
    FirstName = “Joydip”,
    MiddleName = “”,
    LastName = "Kanjilal",
    Department = “Development”,
    Address = “Banjara Hills, Hyderabad, Telengana, INDIA”,
    Phone = “1234567890”
};

Note that, when you create an instance of a record type in C# using positional parameters, the instance becomes immutable by default. Refer to the following source code that shows how you can create an instance of a record type using positional arguments:

var employee = new Employee(1, "Joydip", “”, "Kanjilal", “Development”, "Banjara Hills, Hyderabad, Telengana, India", "0123456789");

The complete source code has been provided below for your reference:

namespace MyRecordDemo
{
    public record Employee
    {
        public int Id { get; init; }
        public string FirstName { get; init; }
        public string MiddleName { get; init; }
        public string LastName { get; init; }
        public string Department { get; init; }
        public string Address { get; init; }
        public string Phone { get; init; }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            Employee employee = new Employee()
            {
                Id = 1,
                FirstName = "Joydip",
                MiddleName = "",
                LastName = "Kanjilal",
                Department = "Development",
                Address = "Banjara Hills",
                Phone = "1234567890"
            };
            Console.WriteLine("Employee Id: {0}",employee.Id);
            Console.WriteLine("First Name: {0}", employee.FirstName);
            Console.WriteLine("Middle Name: {0}",
            employee.MiddleName);
            Console.WriteLine("Last Name: {0}", employee.LastName);
            Console.WriteLine("Department: {0}", employee.Department);
            Console.WriteLine("Address: {0}", employee.Address);
            Console.WriteLine("Phone: {0}", employee.Phone);
            Console.Read();
        }
    }
}

Inheritance in Record Types in C#

Inheritance is a powerful concept in object-oriented programming, allowing you to create reusable pieces of code by deriving from a common base class. Record types can be extended to extend other record types, which is one of their most intriguing features. Therefore, you can create a custom record type inherited from another type (another record type or an interface).

public record FullTimeEmployee : Employee

{
   public int Id { get; init; }
   public int NoOfDaysWorked { get; init; }
   public double GrossSalary { get; init; }
   public double Tax { get; init; }
   public double NetSalary { get; init; }
}

Final Thoughts on C# Record Types

Record types are a great new addition to C#. They make it easier to create immutable value types so that you can pass them around without worrying about immutability. They also help reduce the amount of boilerplate code needed when working with objects that have only a few properties and methods, and at the same time, you want those objects to be immutable.

Read more C# programming tutorials and software development guides.

Joydip Kanjilal
Joydip Kanjilal
A Microsoft Most Valuable Professional in ASP.NET, Speaker, and Author of several books and articles. More than 25 years of experience in IT with more than 18 years in Microsoft .NET and its related technologies. He was selected as a Community Credit Winner at http://www.community-credit.com several times. He has authored 8 books and more than 500 articles in some of the most reputed sites worldwide including MSDN, Info World, CodeMag, Tech Beacon, Tech Target, Developer, CodeGuru, and more.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read