C# String Sınıfı: Neden Referans Tip Ama Değer Tip Gibi Davranıyor? (Ve StringBuilder Hayat Kurtarır)

C# ile biraz haşır neşir olduysanız, mülakatların o meşhur, terleten sorusuyla kesin karşılaşmışsınızdır: “String bir referans (reference) tip midir, yoksa değer (value) tip mi?”

Cevap basit gibi duruyor: String bir sınıftır (class), yani basbayağı bir referans tiptir. Ama iş koda gelince int veya bool gibi, sanki bir değer tipmiş gibi davranır. Peki neden? Arka planda neler dönüyor? Gelin bu kafa karışıklığını bir çözelim.

String Neden Değer Tip Gibi Davranır? (Immutability Meselesi)

Bunun tek kelimelik cevabı var: Immutable (Değiştirilemez) olması.

C#’ta bir string tanımladığınızda, bellekte (Heap üzerinde) o string için bir alan ayrılır. Siz o string’i değiştirdiğinizi sandığınızda, aslında var olan veriyi değiştirmezsiniz. .NET gider, sizin için bellekte yeni bir alan açar, yeni değeri oraya yazar ve eski referansı çöpe (Garbage Collector’a) atar.

Örneğe bakalım:

string isim = "Mehmet";
isim = isim + " Altunel";

Burada isim değişkenine ” Altunel” eklediğimizde, bellekteki “Mehmet” yazısı “Mehmet Altunel” olarak güncellenmez. Aksine;

  1. “Mehmet” bellekte durur.
  2. ” Altunel” için yeni bir yer açılır.
  3. İkisinin birleşimi olan “Mehmet Altunel” için yepyeni, üçüncü bir yer açılır ve isim değişkeni artık burayı işaret eder.

İşte tam da bu yüzden stringler değer tip gibi davranır. Referansı paylaşılan bir nesnenin içeriği değiştirilemediği için, başka bir değişkene atadığınızda beklenmedik yan etkiler (side effects) görmezsiniz.

Peki Sorun Ne? Ne Zaman Patlarız?

Eğer yukarıdaki gibi 2-3 kelime birleştiriyorsanız hiçbir sorun yok. İstediğiniz kadar + operatörünü kullanın. Ama işin içine döngüler girerse, işte o zaman .NET’in hafıza yönetimine (Garbage Collector – GC) eziyet etmeye başlarsınız.

Düşünün ki bir for döngüsü içinde 10.000 kere string birleştiriyorsunuz:

string sonuc = "";
for (int i = 0; i < 10000; i++)
{
    sonuc += i.ToString();
}

Bu kod çalışır mı? Çalışır. Ama arka planda tam 10.000 tane geçici string nesnesi yaratılıp çöpe atılır. Uygulamanızın belleği şişer, GC sürekli temizlik yapmak zorunda kalır ve performans yerlerde sürünür.

Çözüm: Kahramanımız StringBuilder

Eğer yoğun bir string manipülasyonu yapacaksanız, döngüler içinde metin birleştirecekseniz string sınıfını bir kenara bırakıp StringBuilder kullanmalısınız. System.Text namespace’i altında bulunan StringBuilder, mutable (değiştirilebilir) bir yapıya sahiptir. Yani metni güncellediğinizde sürekli yeni bir nesne yaratmaz, var olan bellek alanını genişleterek üzerine yazar.

Aynı kodu StringBuilder ile yazalım:

using System.Text;

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
{
    sb.Append(i.ToString());
}
string sonuc = sb.ToString();

Bu kod, önceki örneğe göre fersah fersah daha hızlı çalışır ve belleği gereksiz yere yormaz.

Özetle;

  • String bir referans tiptir (Class) ama içeriği değiştirilemez (Immutable) olduğu için değer tip gibi güvenli davranır.
  • Basit birleştirmelerde + veya $"{degisken}" (String Interpolation) kullanmakta sakınca yoktur.
  • İşin içine döngüler veya yoğun metin işlemleri giriyorsa, adresiniz kesinlikle StringBuilder olmalıdır.

Umarım faydalı olmuştur. Kodlamaya devam!

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir