C# -

Records

Records are a feature in C# designed to simplify the creation of immutable types and value-like behavior with reference semantics. Introduced in C# 9, records provide a succinct syntax for defining data models and are particularly useful for scenarios where immutability and equality are important.


1. Understanding Records

Records are reference types, similar to classes, but are designed to provide value semantics. This means that two record instances with the same data are considered equal. Records are ideal for defining data models, especially when the data is immutable.

Example:
        
            namespace RecordExamples;

public record Person(string FirstName, string LastName);

class Program
{
    static void Main(string[] args)
    {
        var person1 = new Person("John", "Doe");
        var person2 = new Person("John", "Doe");

        Console.WriteLine(person1 == person2); // Output: True
    }
}
        
    

2. Syntax and Features

Records have a concise syntax and come with several built-in features, such as value equality, with-expressions, and deconstruction.

Example:
        
            namespace RecordExamples;

// Define a record with primary constructor and properties
public record Person(string FirstName, string LastName)
{
    // Additional properties or methods can be added here
    public string FullName => $"{FirstName} {LastName}";
}

class Program
{
    static void Main(string[] args)
    {
        var person = new Person("Jane", "Doe");

        // Value equality
        var anotherPerson = new Person("Jane", "Doe");
        Console.WriteLine(person == anotherPerson); // Output: True

        // With-expression
        var modifiedPerson = person with { LastName = "Smith" };
        Console.WriteLine(modifiedPerson.FullName); // Output: Jane Smith

        // Deconstruction
        var (firstName, lastName) = person;
        Console.WriteLine($"FirstName: {firstName}, LastName: {lastName}"); // Output: FirstName: Jane, LastName: Doe
    }
}
        
    

3. Immutability and Mutation

Records are designed to be immutable by default, meaning their properties cannot be modified after creation. However, C# 10 introduced with-expressions for non-destructive mutation, allowing you to create modified copies of records.

Example:
        
            namespace RecordExamples;

// Define a record
public record Person(string FirstName, string LastName);

class Program
{
    static void Main(string[] args)
    {
        var person = new Person("Alice", "Johnson");

        // Use with-expression to create a modified copy
        var modifiedPerson = person with { LastName = "Smith" };

        Console.WriteLine(modifiedPerson.FirstName); // Output: Alice
        Console.WriteLine(modifiedPerson.LastName);  // Output: Smith
    }
}
        
    

4. Inheritance with Records

Records support inheritance, allowing you to create hierarchies of records. When inheriting from a record, you must use the sealed modifier to prevent further inheritance, or explicitly allow it.

Example:
        
            namespace RecordExamples;

// Base record
public record Person(string FirstName, string LastName);

// Derived record
public record Student(string FirstName, string LastName, string StudentId) : Person(FirstName, LastName);

class Program
{
    static void Main(string[] args)
    {
        var student = new Student("Tom", "Brown", "S12345");

        Console.WriteLine(student); // Output: Student { FirstName = Tom, LastName = Brown, StudentId = S12345 }
    }
}
        
    

5. Positional Records

Positional records provide a compact syntax for defining records with positional parameters in the primary constructor. This approach is especially useful for simple data carriers.

Example:
        
            namespace RecordExamples;

// Define a positional record
public record Point(int X, int Y);

class Program
{
    static void Main(string[] args)
    {
        var point = new Point(3, 4);

        // Value equality
        var anotherPoint = new Point(3, 4);
        Console.WriteLine(point == anotherPoint); // Output: True

        // Deconstruction
        var (x, y) = point;
        Console.WriteLine($"X: {x}, Y: {y}"); // Output: X: 3, Y: 4
    }
}
        
    

6. Best Practices for Using Records



Conclusion

Records in C# are a powerful feature that simplifies the creation of immutable types with value semantics. By understanding their syntax, features, and best practices, you can effectively use records to build clean and efficient data models in your applications.