C# programlama eğitim serimizde Nesne Yönelimli Programlamaya (OOP) giriş yapmış, Sınıflar (Classes) ve Nesneler (Objects) kavramlarını öğrenmiştik. Bir sınıfı “kurabiye kalıbına”, nesneleri ise o kalıptan çıkan “kurabiyelere” benzetmiştik.
Peki, dijital dünyada bir nesnenin “doğum anında” ve “ölüm anında” tam olarak ne olur? Bir nesne bellekte (RAM) var olduğu ilk saniyede ona varsayılan ayarlarını nasıl yükleriz? İşi bittiğinde hafızadan silinirken arkasında bıraktığı dosyaları veya veritabanı bağlantılarını nasıl temizleriz?
İşte bu, bol örnekli ve kapsamlı rehberimizde, nesnelerin yaşam döngüsünü kontrol etmemizi sağlayan Yapıcı Metotlar (Constructors) ve Yıkıcı Metotlar (Destructors / Finalizers) konularını en ince ayrıntısına, hatta modern C# sürümlerindeki en yeni özelliklere kadar inceleyeceğiz.
1. Yapıcı Metot (Constructor) Nedir?
C# dilinde bir sınıftan (class) new anahtar kelimesini kullanarak yeni bir nesne (object) türettiğiniz anda, bilgisayar o nesneyi bellekte oluştururken otomatik olarak çalışan ilk ve özel metoda “Yapıcı Metot” (Constructor) denir.
Nesnenin doğduğu andır. Kurabiye örneğimizden devam edersek; kurabiye fırından çıkar çıkmaz üzerine otomatik olarak damla çikolata serpen mekanizma, yapıcı metottur. Nesnenin başlangıç değerlerini (isim, yaş, bağlantı durumu vb.) atamak için mükemmel bir yerdir.
Yapıcı Metotların 3 Altın Kuralı:
- İsmi, içinde bulunduğu sınıfın (class) ismiyle tamamen aynı olmak zorundadır.
- Hiçbir geri dönüş tipi yoktur (Bırakın
int,stringgibi tipleri,voidkelimesi bile yazılmaz). - Nesne
newkelimesi ile her oluşturulduğunda yalnızca bir kez ve otomatik olarak tetiklenir.
A. Varsayılan Yapıcı Metot (Default Constructor)
Eğer siz bir sınıfın içine hiçbir yapıcı metot yazmazsanız, C# derleyicisi arka planda görünmez, boş bir yapıcı metot oluşturur. Buna varsayılan yapıcı metot denir. Ancak biz bunu kendi elimizle yazarak “nesne doğduğunda” ekrana bir mesaj yazdırabiliriz:
public class Kullanici
{
public string Isim;
// Sınıf ile aynı ada sahip, geri dönüş tipi olmayan metot: CONSTRUCTOR
public Kullanici()
{
Isim = "Bilinmeyen Kullanıcı";
Console.WriteLine("Yeni bir kullanıcı nesnesi bellekte oluşturuldu!");
}
}
// Program.cs içinde kullanımı:
// new Kullanici() yazıldığı anda yapıcı metot tetiklenir.
Kullanici yeniKullanici = new Kullanici();
Console.WriteLine(yeniKullanici.Isim); // Çıktı: Bilinmeyen Kullanıcı
B. Parametreli Yapıcı Metotlar
Nesnelerimiz doğarken onlara dışarıdan bilgi (parametre) göndermek isteyebiliriz. Tıpkı bir araba üretilirken renginin ve motor hacminin baştan fabrikaya bildirilmesi gibi.
public class Araba
{
public string Marka;
public int ModelYili;
// Dışarıdan marka ve yıl bilgisini alan yapıcı metot
public Araba(string markaBilgisi, int yilBilgisi)
{
Marka = markaBilgisi;
ModelYili = yilBilgisi;
Console.WriteLine($"{ModelYili} model {Marka} üretildi.");
}
}
// Artık içi boş "new Araba()" diyemeyiz, çünkü araba doğarken parametre bekliyor!
Araba benimArabam = new Araba("Tesla", 2025);
C. Yapıcı Metotların Aşırı Yüklenmesi (Constructor Overloading)
C# dilinde bir sınıfın birden fazla yapıcı metodu olabilir! Nesneyi isterseniz hiçbir parametre vermeden, isterseniz de tüm parametreleri vererek oluşturmanıza olanak tanıyan bu duruma Overloading (Aşırı Yükleme) denir.
public class Urun
{
public string Ad;
public double Fiyat;
// 1. Yapıcı Metot (Parametresiz)
public Urun()
{
Ad = "İsimsiz Ürün";
Fiyat = 0.0;
}
// 2. Yapıcı Metot (Sadece İsim)
public Urun(string ad)
{
Ad = ad;
Fiyat = 0.0;
}
// 3. Yapıcı Metot (İsim ve Fiyat)
public Urun(string ad, double fiyat)
{
Ad = ad;
Fiyat = fiyat;
}
}
Modern C# Yıldızı: Birincil Kurucular (Primary Constructors)
Programlama dilleri sürekli olarak geliştiricilerin daha az kodla daha çok iş yapabilmesi için güncellenir. C# 12 sürümü ile birlikte hayatımıza harika bir özellik girdi: Birincil Kurucular (Primary Constructors).
Eskiden verileri almak için sınıfın içine uzun uzun field’lar (alanlar) yazar, yapıcı metot açar ve eşleştirme yapardık. C# 12 sayesinde artık yapıcı metot parametrelerini doğrudan sınıf adının yanına yazabilirsiniz. Sınıf veya struct (yapı) tanımlamalarında doğrudan kullanılan bu özellik, kod kalabalığını muazzam ölçüde azaltır.
// C# 12 ve sonrası ile Primary Constructor kullanımı
public class Ogrenci(string ad, string soyad, int okulNo)
{
// Yukarıdan gelen parametreleri doğrudan metotların veya özelliklerin içinde kullanabilirsiniz
public void KendiniTanit()
{
Console.WriteLine($"Benim adım {ad} {soyad}, Numaram: {okulNo}");
}
}
// Kullanımı tamamen aynıdır
var ogrenci1 = new Ogrenci("Ali", "Yılmaz", 1453);
ogrenci1.KendiniTanit();
2. Yıkıcı Metot (Destructor / Finalizer) Nedir?
Yapıcı metotlar nesnenin “doğumunu” temsil ederken, Yıkıcı Metotlar (Destructors veya Finalizers) nesnenin bellekte “ölümünü” (yok edilmesini) temsil eder.
Yıkıcı metotların kuralları çok daha katıdır:
- Sınıf ismiyle aynıdır ancak başına her zaman Tilda (
~) işareti alır (Örn:~Kullanici()). - Erişim belirleyici (
public,private) alamazlar. - Parametre alamazlar (Bu nedenle aşırı yüklenemezler, her sınıfın en fazla 1 tane yıkıcı metodu olabilir).
- Yazılımcı tarafından elle (manuel olarak) çağrılamazlar.
Peki biz çağıramıyorsak bu yıkıcı metodu kim çalıştırıyor? Cevap: Çöp Toplayıcı (Garbage Collector – GC)!
Bellek Yönetimi ve Çöp Toplayıcı (Garbage Collector)
C++ veya C gibi eski nesil dillerde, oluşturduğunuz bir nesneyi işiniz bittiğinde bellekten kendiniz silmek zorundaydınız. Unutursanız “Memory Leak” (Bellek Sızıntısı) denilen çok ciddi sistem hataları olurdu.
C# ve .NET platformu, yüksek performanslı, güvenlik ve güvenilirlik sunacak şekilde tasarlanmıştır ve en büyük artılarından biri otomatik bellek yönetimi sağlayan Garbage Collector’dır (GC). Siz programınızda yeni nesneler ürettikçe GC bunları belleğe yerleştirir; ve ne zaman ki uygulamanızda o nesnelere işaret eden hiçbir referans kalmaz (örneğin metot biter), GC kendi belirlediği bir zamanda gelir ve bu nesneleri bellekten siler.
GC bir nesneyi bellekten tamamen silip yok etmeden milisaniyeler önce, eğer o sınıfın içinde yazılmış bir yıkıcı metot (~SınıfAdi()) varsa, “Son isteğin nedir?” dercesine o metodu çalıştırır.
public class DosyaYonetici
{
// Yapıcı Metot
public DosyaYonetici()
{
Console.WriteLine("Dosya işlemleri için nesne oluşturuldu.");
}
// Yıkıcı Metot (Destructor)
~DosyaYonetici()
{
// Unmanaged (yönetilmeyen) kaynakların temizlenmesi için son şans!
Console.WriteLine("Nesne bellekten siliniyor... Elveda!");
}
}
3. Neden Yıkıcı Metot Yerine IDisposable ve using Kullanmalıyız?
Teoride Yıkıcı metotlar (Destructors) çok güzel görünse de, modern C# projelerinde ve büyük mimarilerde çok nadir kullanılırlar. Neden mi? Çünkü Çöp Toplayıcının (Garbage Collector) ne zaman çalışacağı kesin olarak belli değildir (Non-deterministic).
Bir veritabanı bağlantısı açtığınızı düşünün. Veriyi çektiniz ve işiniz bitti. Bağlantıyı kapatma işini Yıkıcı metoda (Destructor) bırakırsanız, GC belki 3 saniye sonra, belki 3 saat sonra, belki de program kapanırken çalışacaktır. Bu sürede veritabanı bağlantısı açık kalır ve sistem kilitlenir!
Bunu çözmek için C# bize harika bir kontrol mekanizması sunar. Kaynak yönetimini ve temizliğini zamanında yapmak (prompt cleanup) için doğrudan dil destekli IDisposable arayüzünü ve using ifadesini kullanırız.
IDisposable Arayüzü ve using Bloğu ile Kesin Temizlik
Eğer sınıfınızın işi bittiğinde acilen kapatması gereken bir dosya, bir ağ (network) veya veritabanı bağlantısı varsa, sınıfınıza IDisposable yeteneği kazandırmalısınız.
// IDisposable yeteneğini sınıfımıza ekliyoruz
public class VeritabaniBaglantisi : IDisposable
{
public VeritabaniBaglantisi()
{
Console.WriteLine("Veritabanı bağlantısı AÇILDI!");
}
public void VeriGetir()
{
Console.WriteLine("Veriler başarıyla okundu...");
}
// IDisposable bize Dispose adında bir metot yazmayı zorunlu kılar.
// Manuel ve anında temizlik işlemlerini BURAYA yazarız.
public void Dispose()
{
Console.WriteLine("Veritabanı bağlantısı GÜVENLE KAPATILDI!");
}
}
Nasıl Kullanılır? (using Blokları):
using kelimesini bir blok (süslü parantez) olarak kullandığımızda, C# dili o parantez bittiği anda nesneyi yaşatmayı bırakır ve otomatik olarak Dispose() metodunu çağırarak bellek/bağlantı temizliğini anında (saniyesi saniyesine) yapar.
Console.WriteLine("İşlem Başlıyor...");
// using bloğu başlatılıyor.
using (VeritabaniBaglantisi baglanti = new VeritabaniBaglantisi())
{
baglanti.VeriGetir();
} // SÜSLÜ PARANTEZ BİTTİĞİ ANDA Dispose() METODU ÇAĞRILIR!
Console.WriteLine("İşlem Bitti.");
Ekran Çıktısı:
- İşlem Başlıyor…
- Veritabanı bağlantısı AÇILDI!
- Veriler başarıyla okundu…
- Veritabanı bağlantısı GÜVENLE KAPATILDI! (GC’yi beklemeden, o saniye temizlendi)
- İşlem Bitti.
Özet ve Sonuç
C# programlama dilinde Yapıcı Metotlar (Constructors), bir nesneye hayat vermek ve onu başlangıç değerleriyle hazırlamak için vazgeçilmezdir. Özellikle C# 12 ile gelen “Birincil Kurucular” (Primary Constructors) ile bu işlemler artık her zamankinden daha temiz yazılmaktadır.
Nesnenin ölümünü simgeleyen Yıkıcı Metotlar (Destructors / Finalizers) ise Çöp Toplayıcı’nın inisiyatifinde çalıştığı için modern iş akışlarında kontrolsüzdür. Bu nedenle profesyonel C# geliştiricileri; bağlantılar, dosya okumaları veya bellek yükü olan ağır nesnelerde her zaman IDisposable mimarisini ve using bloklarını kullanarak temizliği yönetirler.
Nesnelerin doğumunu ve ölümünü kontrol etmeyi öğrendiğinize göre, artık profesyonel C# yazılımcısı olma yolunda büyük bir engeli aştınız. Bir sonraki içeriğimizde sınıfların özelliklerini bir başka sınıfa nasıl aktardığımızı (Kalıtım / Inheritance) inceleyeceğiz! Bol kodlamalı günler.




