Record Types
Record types are a modern C# feature designed for working with data-focused objects. They provide built-in support for value-based equality and make it easier to create immutable data models.
Records are particularly useful when the main purpose of a type is to represent and transfer data rather than contain complex mutable behavior.
Creating a Record
A record can be declared using the
record keyword.
public record Student
{
public int Id { get; init; }
public string Name { get; init; }
public string Course { get; init; }
}
The init accessor allows a property to be set
during object initialization but prevents normal
modification afterward.
Creating a Record Object
using System;
class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Course { get; set; }
}
class Program
{
static void Main()
{
Student student = new Student
{
Id = 101,
Name = "Pradnya",
Course = "Dot.Net Full Stack"
};
Console.WriteLine(student.Name);
Console.WriteLine(student.Course);
}
}
Output
Pradnya
Dot.Net Full Stack
Positional Records
C# also provides a shorter syntax called a positional record. Properties are declared directly in the record declaration.
using System;
public record Student(
int Id,
string Name,
string Course
);
class Program
{
static void Main()
{
Student student =
new Student(101, "Pradnya", "Dot.Net Full Stack");
Console.WriteLine(student.Id);
Console.WriteLine(student.Name);
Console.WriteLine(student.Course);
}
}
Output
101
Pradnya
Dot.Net Full Stack
Value-Based Equality
One of the important features of records is value-based equality. Two record objects containing the same values are considered equal.
using System;
public record Student(
int Id,
string Name
);
class Program
{
static void Main()
{
Student student1 =
new Student(101, "Rahul");
Student student2 =
new Student(101, "Rahul");
Console.WriteLine(student1 == student2);
}
}
Output
True
Class vs Record
| Feature | Class | Record |
|---|---|---|
| Primary Purpose | General-purpose objects | Data-focused objects |
| Equality | Reference-based by default | Value-based by default |
| Immutable Style | Must be designed manually | Supported naturally with init properties |
| Syntax | More verbose | Can be concise |
with Expression
The with expression creates a new record
object based on an existing record while changing one or
more values.
using System;
public record Student(
int Id,
string Name,
string Course
);
class Program
{
static void Main()
{
Student student1 =
new Student(101, "Rahul", "Java");
Student student2 =
student1 with
{
Course = "C# Full Stack"
};
Console.WriteLine(student1.Course);
Console.WriteLine(student2.Course);
}
}
Output
Java
C# Full Stack
The original record remains unchanged, while
student2 contains the modified value.
ToString() with Records
Records provide a useful generated
ToString() implementation that displays
the record type and its values.
using System;
public record Student(
int Id,
string Name,
string Course
);
class Program
{
static void Main()
{
Student student =
new Student(101, "Rahul", "C# Full Stack");
Console.WriteLine(student);
}
}
Output
Student { Id = 101, Name = Rahul, Course = C# Full Stack }
Immutability
Records are commonly used with immutable data. Once an object has been initialized, its values can be kept unchanged.
using System;
public record Employee(
int Id,
string Name
);
class Program
{
static void Main()
{
Employee employee =
new Employee(1, "Amit");
// employee.Name = "Rahul"; // Not allowed
Console.WriteLine(employee.Name);
}
}
Output
Amit
Records in ASP.NET Core Web API
Records are useful for DTOs (Data Transfer Objects) in ASP.NET Core applications.
A DTO represents the data that should be transferred between the client and server.
public record StudentDto(
int Id,
string Name,
string Course
);
A controller can return the record as an API response.
[HttpGet]
public IActionResult GetStudent()
{
StudentDto student =
new StudentDto(
101,
"Rahul",
"C# Full Stack"
);
return Ok(student);
}
JSON Response
{
"id": 101,
"name": "Rahul",
"course": "C# Full Stack"
}
Record Class and Record Struct
A record can be a reference type or a value type.
record creates a record class, while
record struct creates a record value type.
public record class Student(
int Id,
string Name
);
public record struct Point(
int X,
int Y
);
| Type | Category |
|---|---|
| record class | Reference type |
| record struct | Value type |
When Should You Use Records?
- When the type mainly represents data.
- When value-based equality is useful.
- When immutable data is preferred.
- When creating DTOs for Web APIs.
- When concise data model syntax improves readability.
When Should You Prefer a Class?
- When the object has significant mutable state.
- When identity is more important than value equality.
- When the type represents a complex domain entity.
- When object behavior is the primary focus.
Common Mistakes
- Assuming records are completely immutable in every possible design.
- Using records for every class in an application.
- Confusing value equality with reference identity.
- Modifying data directly when immutable design is intended.
- Using a record where entity identity and lifecycle are more important.
Best Practices
- Use records primarily for data-oriented types.
- Prefer immutable properties when appropriate.
- Use records for DTOs where value semantics are useful.
-
Use
withexpressions when creating modified copies of records. - Choose classes when object identity and mutable behavior are central to the design.
Interview Questions
1. What is a record in C#?
A record is a data-oriented type that provides value-based equality and convenient syntax for immutable-style objects.
2. What is the main difference between a class and a record?
A class uses reference-based equality by default, while a record provides value-based equality.
3. What is a positional record?
A positional record is a concise record declaration in which its primary data properties are declared directly in the record header.
4. What is the with expression?
The with expression creates a new record based on an existing record while allowing selected values to be changed.
5. What is value-based equality?
Value-based equality means objects are considered equal when their relevant data values are equal.
6. What is a record struct?
A record struct is a value-type record that combines record-style value equality with struct semantics.
7. Why are records useful in ASP.NET Core?
Records are useful for representing DTOs and other data-transfer models where value-based semantics and concise immutable-style definitions are beneficial.
Practice Programs
- Create a Student positional record.
- Create two records with the same values and compare them.
- Create a new record using the with expression.
- Create an Employee record with Id, Name, and Department.
- Create a Product record and display it using ToString().
- Create a record DTO and return it from an ASP.NET Core Web API controller.
- Create a record struct representing a Point with X and Y.
Summary
Record types are designed for data-focused objects and provide value-based equality by default.
You learned standard records, positional records, value-based equality, immutable-style properties, with expressions, and generated ToString() behavior.
You also learned the difference between record class and record struct.
Records are especially useful for DTOs and data-transfer models in modern C# and ASP.NET Core applications.