Structs and Records
Overview
Structs and records are types in C# that provide different ways of modeling data. Structs are value types, while records are reference types with built-in structural equality. Understanding their use cases can help in choosing the right type for a given scenario.
Structs
Value Types
Structs are value types, meaning they are stored on the stack and copied by value. They are typically used for small, immutable data structures and have better performance for such scenarios compared to classes.
Syntax
Structs are defined using the struct
keyword, followed by the struct name and its body enclosed in curly braces {}
.
Example
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
Equality
Structs support value equality by default. This means two structs are considered equal if all their fields are equal.
Example
Point point1 = new Point { X = 5, Y = 10 };
Point point2 = new Point { X = 5, Y = 10 };
Console.WriteLine(point1 == point2); // True
point1.Equals(point2); // True
Mutability
Structs can be mutable, but it is recommended to use immutable structs to prevent unintended side effects. An immutable struct has readonly
fields or properties and does not change after initialization.
public struct Point
{
public int X { get; } //look ma, no setter!
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
}
Records
Reference Types with Structural Equality
Records are reference types that provide value-based equality semantics. They are ideal for data models that do not require behavior (e.g. methods) and are mainly used to encapsulate immutable data.
Syntax
Records are defined using the record
keyword, followed by the record name and its body enclosed in curly braces {}
.
Example
public record Person(string Name, int Age);
With Expressions
The with
expression allows you to create a new record based on an existing record, with modifications to some properties.
Example
var person1 = new Person("John Doe", 30);
var person2 = person1 with { Age = 31 };
Console.WriteLine(person1); // Person { Name = John Doe, Age = 30 }
Console.WriteLine(person2); // Person { Name = John Doe, Age = 31 }
Structural Equality
Records provide built-in value equality, which means two records are considered equal if all their properties are equal.
Example
var person1 = new Person("John Doe", 30);
var person2 = new Person("John Doe", 30);
Console.WriteLine(person1 == person2); // True
person1.Equals(person2); // True
Records vs. Classes vs. Structs
Structs
- Performance: Best suited for small, immutable data types due to value semantics.
- Use Cases: High-performance scenarios, geometric points, complex numbers.
Records
- Data-Centric: Best for immutable data models that do not require behavior.
- Use Cases: DTOs (data transfer objects), configuration objects, immutable data transfers.
Classes
- Flexibility: Ideal for complex objects with behavior and mutable state.
- Use Cases: Domain models, services, business logic.