VodiSoft
In modern C# and .NET development, class and record serve different architectural purposes. This article explains the core differences between them, including reference vs value equality, mutable vs immutable design, DTO and Entity usage, CQRS patterns, and real-world software architecture examples. You’ll learn when to use class, when to prefer record, and how professional .NET applications structure their models efficiently.

C# Class vs Record: Differences, Use Cases, and Real-World Project Examples

In this article, we will explore the differences between class and record in C# with practical software development examples.


1. What is a Class?

A class is the fundamental reference type in C# used for creating objects.

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
}

var user1 = new User { Id = 1, Name = "Emre" };
var user2 = user1;

user2.Name = "Ahmet";

Console.WriteLine(user1.Name); // Ahmet

Both variables reference the same object in memory.


2. What is a Record?

record was introduced in C# 9 and is designed primarily for data-centric models.

public record UserDto(int Id, string Name);

var user1 = new UserDto(1, "Emre");
var user2 = new UserDto(1, "Emre");

Console.WriteLine(user1 == user2); // True

Records provide value-based equality by default.


3. The Core Difference Between Class and Record

For a class:

Is this the same object?

For a record:

Do these objects contain the same data?

Example:

public class ProductClass
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public record ProductRecord(int Id, string Name);
var c1 = new ProductClass { Id = 1, Name = "Laptop" };
var c2 = new ProductClass { Id = 1, Name = "Laptop" };

var r1 = new ProductRecord(1, "Laptop");
var r2 = new ProductRecord(1, "Laptop");

Console.WriteLine(c1 == c2); // False
Console.WriteLine(r1 == r2); // True

4. Why Classes Are Better for Mutable Objects

Classes are typically used for objects whose state changes over time.

public class Basket
{
    public int Id { get; set; }
    public List<string> Products { get; set; } = new();

    public void AddProduct(string product)
    {
        Products.Add(product);
    }
}

5. Why Records Are Better for Immutable Data

Records are ideal for DTOs, requests, responses, and value objects.

public record CreateUserRequest(string Name, string Email);

6. Using the with Expression

One of the most powerful features of records is the with expression.

public record UserDto(int Id, string Name, string Email);

var user1 = new UserDto(1, "Emre", "[email protected]");

var user2 = user1 with
{
    Email = "[email protected]"
};

This allows immutable-style object updates.


7. ToString Differences

Class:

Console.WriteLine(user);
// Namespace.UserClass

Record:

Console.WriteLine(user);
// UserRecord { Id = 1, Name = Emre }

Records provide cleaner debug output by default.


8. Built-in Deconstruction Support

Records automatically support deconstruction.

public record UserDto(int Id, string Name);

var user = new UserDto(1, "Emre");

var (id, name) = user;

9. Why Entities Usually Use Classes

Entities are identity-based and behavior-oriented.

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }

    public decimal Price { get; set; }

    public void ChangePrice(decimal newPrice)
    {
        if (newPrice <= 0)
            throw new ArgumentException();

        Price = newPrice;
    }
}

Entities contain business logic and mutable state.


10. Why DTOs Are Great Candidates for Records

public record ProductResponse(
    int Id,
    string Name,
    decimal Price
);

DTOs mainly carry data and rarely contain behavior.


11. Records for Value Objects

public record Money(decimal Amount, string Currency);
var money1 = new Money(100, "TRY");
var money2 = new Money(100, "TRY");

Console.WriteLine(money1 == money2); // True

Value objects are naturally value-based.


12. Why Services and Repositories Should Be Classes

public class PaymentService
{
    public void Pay(decimal amount)
    {
        // payment logic
    }
}

Services contain behavior, not just data.


13. Records in CQRS and MediatR

public record CreateProductCommand(
    string Name,
    decimal Price
);
public record GetProductByIdQuery(int Id);

14. record class vs record struct

public record Person(string Name);

public record struct Point(int X, int Y);

public readonly record struct Coordinate(int X, int Y);
  • record class → reference type
  • record struct → value type

15. Real-World Project Example

Entity:

public class Order
{
    public int Id { get; private set; }
    public int CustomerId { get; private set; }
    public decimal TotalAmount { get; private set; }
    public string Status { get; private set; }

    public void Approve()
    {
        if (Status != "Pending")
            throw new InvalidOperationException();

        Status = "Approved";
    }
}

DTO:

public record OrderResponse(
    int Id,
    int CustomerId,
    decimal TotalAmount,
    string Status
);

Command:

public record CreateOrderCommand(
    int CustomerId,
    List<int> ProductIds
);

Value Object:

public record OrderPrice(decimal Amount, string Currency);

16. Quick Decision Table

Scenario Preferred Type
Entity class
Service class
Repository class
Mutable Object class
DTO record
API Request record
API Response record
Value Object record
Event Model record
Command/Query record

17. Final Rule of Thumb

Use class when:

  • Identity matters
  • The object contains behavior
  • The object changes over time

Use record when:

  • The object only carries data
  • You prefer immutable design
  • Value-based equality is needed

Practical mindset:

Does this object perform actions? → class
Does this object only carry data? → record
Does identity matter? → class
Do values matter more? → record

In professional .NET projects, the most common approach is:

  • class for entities, services, repositories, and behavior-heavy models
  • record for DTOs, requests, responses, commands, queries, and value objects

18. Quick Decision Table

Scenario Preferred Type
Entity class
Service class
Repository class
Controller class
Manager class
Mutable Object class
DTO record
API Request/Response record
Value Object record
Event Model record
Command/Query Model record
Config/Options Model class or record
EF Core Entity usually class
Log/Event Payload record

19. Real-World Project Example

Entity:

public class Order
{
    public int Id { get; private set; }
    public int CustomerId { get; private set; }
    public decimal TotalAmount { get; private set; }
    public string Status { get; private set; }

    public void Approve()
    {
        if (Status != "Pending")
            throw new InvalidOperationException("Only pending orders can be approved.");

        Status = "Approved";
    }
}

DTO:

public record OrderResponse(
    int Id,
    int CustomerId,
    decimal TotalAmount,
    string Status
);

Command:

public record CreateOrderCommand(
    int CustomerId,
    List<int> ProductIds
);

Value Object:

public record OrderPrice(decimal Amount, string Currency);

The distinction here is clear:

  • Order is an entity → class
  • OrderResponse carries data → record
  • CreateOrderCommand carries data → record
  • OrderPrice is a value object → record

20. The Most Practical Rule

Use class when:

  • Identity matters
  • The object contains behavior
  • The object changes over time

Use record when:

  • The object only carries data
  • You prefer immutable design
  • You need value-based equality

A practical mindset:

Does this object perform actions? → class
Does this object only carry data? → record
Does identity matter? → class
Do values matter more? → record
Does the object change over time? → class
Should the object remain immutable after creation? → record

In professional .NET projects, the most common approach is:

  • Use class for entities, services, repositories, and behavior-heavy models
  • Use record for DTOs, requests, responses, commands, queries, and value objects

Related Articles

What Are C# Union Types? Type-Safe State Management in Modern .NET Applications

In this article, we deeply explore the new Union Types concept in C#. You will learn what Union Types are, which problems they solve, how they differ from class and record structures, how they can be used in API response models, and how they relate to the Result Pattern. We also cover when Union Types should or should not be used, with real-world examples from payment systems, authentication flows, CQRS, validation, domain-driven design, and modern state management scenarios in .NET applications.

Read More

.NET MAUI vs Avalonia UI: Which One Should You Choose as of 2026?

Two giant cross-platform framework options stand out for developers looking to build desktop and mobile applications within the .NET ecosystem: .NET MAUI and Avalonia UI. As VodiSoft, we have prepared an in-depth comparison to help you make the best architectural choice under the light of latest 2026 software trends.

Read More

VodiSoft

Turn your software idea into a revenue-generating product

For web, mobile, .NET, SaaS and integration projects, we can map the risks, timeline and fastest path to commercial value.

Get a Quote Meeting