C# Records vs Classes: Veri Yönetiminde Modern Yaklaşım

Biz yazılım geliştiriciler olarak çoğu zaman veri taşımak amacıyla sınıflar oluştururuz. Oluşturduğumuz bu sınıflar genellikle iş mantıklarını içermez. Sadece o sınıfa ait Id, Name, Surname gibi özellikleri içerir. Aşağıda bir sınıf için yaptığımız genel bir tanımlama mantığını paylaşıyorum.
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Surnama { get; set; }
}C# 9 ile gelen Record türleri ise tam olarak bu senaryo için tasarlanmış. Bu yazımızda uzun yıllardır kullandığımız Class varken neden Record kullanalım sorusuna cevap arayacağız.
Class ve Record Arasındaki Temel Fark: Referans, Değer Eşitliği
Aradaki en büyük fark eşitlik. Class varsayılan olarak referans eşitliğini kullanır. Yani iki sınıf içerisindeki veriler birebir aynı olsa bile, bellekteki adresleri farklıysa bu iki nesne "eşit değil" olarak kabul edilir.
Record ise varsayılan olarak değer eşitliğini kullanır. Yani iki record bellekte farklı yerlerse olsa bile, içerdikleri veriler aynı ise bu iki nesne "eşit" kabul edilir.
Şimdi bu anlattıklarımızı kod üzerinden açıklamaya çalışalım. İlk olarak UserClass ve UserRecord oluşturarak oluşturalım.
public class UserClass
{
public string Name { get; set; }
public string Surname { get; set; }
public UserClass(string name, string surname)
{
Name = ad;
Surname = soyad;
}
}public record UserRecord(string Name, string Surname);Şimdi tanımlamış olduğumuz Class üzerinden aşağıdaki kod bloğunu deneyelim.
var user1 = new UserClass("Yusuf", "İşleyen");
var user2 = new UserClass("Yusuf", "İşleyen");
Console.WriteLine(user1 == user2);Bu kodu çalıştırdığınızda sonucun false döndüğünü göreceksiniz. Çünkü bunun sebebi Class için veriler aynı da olsa bellekte farklı adreste tutulduğu için eşit olarak kabul edilmiyor.
var record1 = new UserRecord("Yusuf", "İşleyen");
var record2 = new UserRecord("Yusuf", "İşleyen");
Console.WriteLine(record1 == record2);Şimdi de üstteki kod bloğunun nasıl davranacağını açıklayalım. Bu kodu çalıştırdığınızda ekranda true ifadesini göreceksiniz. Bunun sebebi ise Record burada Ad ve Soyad aynı ise bunlar aynı kişidir mantığı ile çalışıp değişkenlerin birbirine eşit olduğu bilgisini ekrana yazacak.
Şimdi de Record olarak tanımlanan bir değişkenin içerisindeki değeri nasıl değiştireceğimize bakalım. Yukarıda tanımladığımız UserRecord tanımındaki özellikler init modundadır. Yani nesne oluşturulduktan sonra Name değeri de Surname değerini değiştiremezsiniz.
Peki bu veriyi değiştirmemiz gerekirse ne yapmamız gerekiyor. Burada ortaya with anahtar kelimesi devreye giriyor. With anahtar sözcüüğü yine de var olan nesneyi değiştirmemize imkan vermiyor. Sadece istediğimiz alanı değiştirip yeni bir kopya almamız sağlıyor.
var originalUser = new UserRecord("Yusuf", "İşleyen");
originalUser.Name = "Batur";
Console.WriteLine(originalUser);Bu kodu derlemek istediğinizde "Init-only property or indexer 'UserRecord.Name' can only be assigned in an object initializer, or on 'this' or 'base' in an instance constructor or an 'init' accessor." bu şekilde bir hata ile karşılacaksınız. Burada UserRecord içerisindeki Name alanının init bir değer olduğu ve başlangıçta atanabileceği mesajı yer alıyor. Doğru yöntem ise aşağıdaki şekilde olmalı.
var originalUser = new UserRecord("Yusuf", "İşleyen");
var newUser = originalUser with { Name = "Batur" };
Console.WriteLine(originalUser);
Console.WriteLine(newUser);Bu kodu derlemek istediğiniz de ise herhangi bir hata ile karşılaşmayacaksınız. Çıktı olarak da newUser değerini UserRecord { Name = Batur, Surname = İşleyen } şeklinde ekrana yazdıracak.
Ne Zaman Class, Ne Zaman Record Kullanmalı?
| Özellik | Record | Class |
| Amaç | Veri taşımak, DTO'lar, API yanıtları vb. yerlerde | İş mantığı, servisler, yöneticiler vb. yerlerde |
| Değişim | Verinin oluşturulduktan sonra değişmemesi gerekiyor ise. | Nesne durumunun sık sık değişmesi gerekiyorsa |
| Eşitlik | "İçerik aynıysa eşittir" demek isteniyor ise | "Sadece aynı bellek adresindeyse eşittir" demek isteniyor ise |
Kısa bir özet geçmem gerekir ise Record tipleri, kodunuzu daha okunabilir, daha kısa ve hatalara karşı daha güvenli hale getirir. Özellikle "Value Object" veya "DTO" olarak kullandığınız sınıfları Record'a dönüştürmek, projenizin modernleşmesi adına atılacak bir adım olabilir.