VodiSoft
C# dünyasında class ve record, farklı amaçlar için kullanılan iki önemli veri modelleme yaklaşımıdır. Bu yazıda class ve record yapılarının çalışma mantığını, referans ve değer bazlı eşitlik farklarını, immutable yapı kullanımını, DTO ve Entity senaryolarını, gerçek proje örneklerini ve profesyonel kullanım stratejilerini detaylı şekilde inceleyeceğiz. Özellikle modern .NET projelerinde hangi durumda class, hangi durumda record tercih edilmesi gerektiğini pratik örneklerle açıklayacağız.

C# Class vs Record: Farkları, Kullanım Senaryoları ve Gerçek Proje Örnekleri

Aşağıda C# açısından class ve record konusunu pratik proje mantığıyla anlatıyorum.

1. Class nedir?

class, C#’ta nesne üretmek için kullanılan temel referans tipidir. Bir class’tan oluşturulan nesne bellekte heap üzerinde tutulur; değişken ise nesnenin kendisini değil, o nesneye giden referansı taşır.

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


Burada `user1` ve `user2` aynı nesneyi gösterir.

---

## 2. Record nedir?

`record`, C# 9 ile gelen ve özellikle veri taşıyan modeller için tasarlanmış özel bir türdür.

```csharp
public record UserDto(int Id, string Name);

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

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

Record’larda varsayılan olarak değer bazlı eşitlik vardır.


3. Class ve Record arasındaki temel fark

Class için kimlik önemlidir:

Bu aynı nesne mi?

Record için veri önemlidir:

Bu nesnenin içindeki bilgiler aynı mı?

Örnek:

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. Mutable yapı için class kullanımı

Class genellikle değiştirilebilir nesneler için uygundur.

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

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

5. Immutable veri için record kullanımı

Record özellikle DTO, request, response ve value object gibi yapılarda idealdir.

public record CreateUserRequest(string Name, string Email);

6. with kullanımı

Record’ların güçlü özelliklerinden biri with ifadesidir.

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

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

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

Bu yapı immutable çalışma mantığında oldukça değerlidir.


7. ToString farkı

Class:

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

Record:

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

8. Deconstruction desteği

Record’lar otomatik deconstruct desteği sunar.

public record UserDto(int Id, string Name);

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

var (id, name) = user;

9. Entity için neden class tercih edilir?

Entity’lerde kimlik önemlidir.

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;
    }
}

Entity’ler davranış içerir ve zamanla değişebilir.


10. DTO için neden record uygundur?

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

DTO yapıları çoğunlukla sadece veri taşır.


11. Value Object için record kullanımı

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

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

12. Service ve Repository neden class olur?

public class PaymentService
{
    public void Pay(decimal amount)
    {
        // ödeme işlemi
    }
}

Service ve repository yapıları davranış taşır.


13. CQRS tarafında record kullanımı

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

14. record class ve record struct farkı

public record Person(string Name);

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

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

15. Gerçek proje örneği

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. Kısa karar tablosu

Senaryo Tercih
Entity class
Service class
Repository class
Mutable nesne class
DTO record
API Request record
API Response record
Value Object record
Event modeli record
Command/Query record

17. En net kullanım kuralı

Class kullan:

  • Nesnenin kimliği önemliyse
  • Nesne davranış içeriyorsa
  • Nesne zamanla değişiyorsa

Record kullan:

  • Nesne sadece veri taşıyorsa
  • Immutable yapı istiyorsan
  • Değer bazlı equality gerekiyorsa

Pratikte şöyle düşünebilirsin:

Bu nesne iş yapıyor mu? → class
Bu nesne sadece veri mi taşıyor? → record
Bu nesnenin identity'si önemli mi? → class
Bu nesnenin değerleri önemli mi? → record

Modern .NET projelerinde profesyonel yaklaşım genellikle şu şekildedir:

  • Entity, service ve davranış içeren yapılarda → class
  • DTO, request, response, command, query ve value object yapılarında → record

18. Kısa karar tablosu

Senaryo Tercih
Entity class
Service class
Repository class
Controller class
Manager class
Mutable nesne class
DTO record
API Request/Response record
Value Object record
Event modeli record
Command/Query modeli record
Config/options modeli class veya record
EF Core entity genellikle class
Log/event payload record

19. Gerçek proje örneği

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);

Burada ayrım nettir:

  • Order bir entity’dir → class
  • OrderResponse veri taşır → record
  • CreateOrderCommand veri taşır → record
  • OrderPrice değer nesnesidir → record

20. En net kural

Class kullan:

  • Nesnenin kimliği önemliyse
  • Nesne davranış içeriyorsa
  • Nesne zamanla değişiyorsa

Record kullan:

  • Nesne sadece veri taşıyorsa
  • Immutable yapı istiyorsan
  • Değer bazlı equality gerekiyorsa

Pratikte şöyle düşünebilirsin:

Bu nesne iş yapıyor mu? → class
Bu nesne sadece veri mi taşıyor? → record
Bu nesnenin identity'si önemli mi? → class
Bu nesnenin değerleri önemli mi? → record
Bu nesne zamanla değişiyor mu? → class
Bu nesne oluşturulduktan sonra sabit kalmalı mı? → record

Modern .NET projelerinde profesyonel yaklaşım genellikle şu şekildedir:

  • Entity, service ve davranış içeren yapılarda → class
  • DTO, request, response, command, query ve value object yapılarında → record