Giriş: Nesnelerin Doğuş Anı

Bir sınıfı, bir nesnenin nasıl olması gerektiğine dair bir plan veya şablon olarak düşünebiliriz. Örneğin, bir Araba sınıfı, bir arabanın marka, model, renk gibi özelliklere ve hızlan, yavaşla gibi metotlara sahip olacağını tanımlar. Ancak bu plan tek başına bir işe yaramaz; bu plandan gerçek, somut arabalar oluşturmamız gerekir. İşte bu oluşturma işlemine örnekleme (instantiation) denir ve C#’ta new anahtar kelimesi ile yapılır.

new Araba(“Kırmızı”, “Ferrari”) gibi bir ifade yazdığımızda, arka planda .NET çalışma zamanı (CLR) şunları yapar:

Heap bellekte Araba nesnesi için yeterli alanı ayırır.
Bu yeni nesne için uygun yapıcı metodu (constructor) bulur ve çağırır.
Yapıcı metot, nesnenin alanlarına (fields) başlangıç değerlerini atar, gerekli ayarlamaları yapar ve nesneyi kullanıma hazırlar.
new operatörü, Heap’teki bu yeni oluşturulmuş ve başlatılmış nesnenin referansını (bellek adresini) döndürür.
Yapıcı metotlar, nesnenin “doğduğu” anda çağrılan ve onun ilk kurulumunu yapan özel fonksiyonlardır. Onlar olmadan, nesnelerimiz başlangıçta tanımsız veya geçersiz bir durumda olabilirdi.

Bölüm 1: Yapıcı Metotların Temel Özellikleri ve Söz Dizimi

1.1. Tanım:

Yapıcı metot, bir sınıftan yeni bir nesne örneği oluşturulduğunda otomatik olarak yürütülen özel bir metottur.
Birincil görevi, nesnenin alanlarını başlatmak ve nesnenin geçerli bir başlangıç durumuna sahip olmasını sağlamaktır.
1.2. Temel Söz Dizimi:

[erişim_belirleyici] SinifAdi([parametre_listesi]) [ : yapıcı_başlatıcı(...) ]
{
// Yapıcı metot gövdesi:
// - Alanlara başlangıç değerleri atama
// - Gerekli diğer başlangıç işlemleri
}
erişim_belirleyici: Yapıcının nereden çağrılabileceğini belirler (public, private, protected, internal). Genellikle public olur, böylece sınıfın örnekleri her yerden oluşturulabilir. private yapıcılar, Singleton deseni gibi özel durumlar için kullanılır (nesne oluşturmayı sınıfın içine kısıtlar).
SinifAdi: Yapıcı metodun adı, her zaman ait olduğu sınıfın adıyla aynı olmalıdır. Bu, derleyicinin onu normal bir metottan ayırt etmesini sağlar.
Geri Dönüş Türü Yok: Yapıcı metotların hiçbir zaman bir geri dönüş türü olmaz ( void bile yazılmaz). Görevleri nesneyi başlatmaktır, bir değer döndürmek değil (new operatörü nesne referansını döndürür).
parametre_listesi: Nesne oluşturulurken dışarıdan başlangıç değerleri almak için kullanılır. Parametreler normal metotlardaki gibi tanımlanır (tür ad, tür ad, …).
: yapıcı_başlatıcı(…) : Aynı sınıftaki başka bir yapıcıyı (this(…)) veya temel (üst) sınıftaki bir yapıcıyı (base(…)) bu yapıcı çalışmadan önce çağırmak için kullanılır (Bölüm 4).
{ … } (Yapıcı Gövdesi): Yapıcı çağrıldığında çalıştırılacak kodları içerir. Genellikle parametrelerden gelen değerler sınıfın alanlarına veya özelliklerine atanır.
Örnek:

public class Oyuncu
{
// Alanlar
private string _kullaniciAdi;
private int _seviye;
private DateTime _kayitTarihi;
// Public Yapıcı Metot (Constructor)
public Oyuncu(string kullaniciAdi)
{
Console.WriteLine($"'{kullaniciAdi}' için Oyuncu nesnesi oluşturuluyor...");
// Alanları başlatma
_kullaniciAdi = kullaniciAdi;
_seviye = 1; // Varsayılan başlangıç seviyesi
_kayitTarihi = DateTime.Now; // O anki tarih/saat
Console.WriteLine("Oyuncu nesnesi başarıyla oluşturuldu.");
}
// Özellikler (Alanlara erişim için)
public string KullaniciAdi => _kullaniciAdi; // Read-only kısayol
public int Seviye => _seviye;
public DateTime KayitTarihi => _kayitTarihi;
// Metot
public void SeviyeAtla()
{
_seviye++;
Console.WriteLine($"{_kullaniciAdi} seviye atladı! Yeni seviye: {_seviye}");
}
}
// Kullanım
Oyuncu oyuncu1 = new Oyuncu("Kahraman123"); // Yapıcı metot burada çağrılır
Console.WriteLine($"Oyuncu Adı: {oyuncu1.KullaniciAdi}");
Console.WriteLine($"Başlangıç Seviyesi: {oyuncu1.Seviye}");
oyuncu1.SeviyeAtla();
Bölüm 2: Yapıcı Metot Türleri

C#’ta farklı ihtiyaçlara yönelik çeşitli yapıcı metot türleri bulunur.

2.1. Varsayılan Yapıcı (Default Constructor)

Eğer bir sınıf için hiçbir yapıcı metot açıkça tanımlanmazsa, C# derleyicisi otomatik olarak parametresiz, public bir varsayılan yapıcı oluşturur.
Bu varsayılan yapıcı, sınıfın tüm alanlarını kendi türlerinin varsayılan değerlerine ayarlar (sayısal tipler için 0, bool için false, referans tipleri ve nullable değer tipleri için null, char için ‘\0’).
ÖNEMLİ: Siz sınıfa herhangi bir yapıcı metot (parametreli veya parametresiz) tanımladığınız anda, derleyici artık varsayılan yapıcıyı oluşturmaz. Eğer parametresiz bir yapıcıya hala ihtiyacınız varsa (örneğin bazı kütüphaneler veya serileştirme mekanizmaları bunu gerektirebilir), onu açıkça kendiniz tanımlamanız gerekir.
public class BasitSinif
{
public int Sayi;
public string Metin;
public bool Durum;
}
// Kullanım:
BasitSinif b = new BasitSinif(); // Derleyicinin oluşturduğu varsayılan yapıcı çağrılır
Console.WriteLine($"Sayı: {b.Sayi}, Metin: {b.Metin ?? "null"}, Durum: {b.Durum}");
// Çıktı: Sayı: 0, Metin: null, Durum: False
public class YapicisizOlmaz
{
public string Mesaj { get; set; }
// Parametreli yapıcıyı biz tanımladık
public YapicisizOlmaz(string ilkMesaj)
{
Mesaj = ilkMesaj;
}
// Artık derleyici varsayılan parametresiz yapıcıyı OLUŞTURMAZ!
}
// Kullanım:
// YapicisizOlmaz y = new YapicisizOlmaz(); // HATA! Uygun parametresiz yapıcı yok.
YapacisizOlmaz y2 = new YapicisizOlmaz("Merhaba"); // Geçerli
2.2. Parametreli Yapıcı (Parameterized Constructor)

Nesne oluşturulurken başlangıç değerlerini dışarıdan almak için bir veya daha fazla parametre alan yapıcılardır.
En yaygın kullanılan yapıcı türüdür. Nesnelerin başlangıçta geçerli ve anlamlı bir duruma sahip olmasını sağlar.
Yukarıdaki Ogrenci ve Kitap örneklerindeki yapıcılar parametreli yapıcılardır.
2.3. Yapıcı Aşırı Yüklemesi (Constructor Overloading)

Bir sınıfın, farklı parametre listelerine (parametre sayısı, türleri veya sırası farklı) sahip birden fazla yapıcı metoda sahip olabilmesidir.
Bu, nesneleri farklı başlangıç bilgileriyle oluşturmak için esneklik sağlar.
Hangi yapıcının çağrılacağına, new ifadesiyle birlikte kullanılan argümanların sayısı ve türleri karar verir.
Yukarıdaki Kitap sınıfı örneği, yapıcı aşırı yüklemesini gösterir (parametresiz, iki parametreli, üç parametreli yapıcılar).
2.4. Kopya Yapıcı (Copy Constructor) — Bir Desen

C#’ta doğrudan bir “kopya yapıcı” anahtar kelimesi yoktur, ancak bu bir tasarım desenidir.
Amacı, mevcut bir nesnenin değerlerini kopyalayarak yeni bir nesne örneği oluşturmaktır.
Genellikle aynı sınıftan başka bir nesneyi parametre olarak alan bir yapıcıdır ve bu parametrenin özelliklerini yeni oluşturulan nesnenin özelliklerine kopyalar.
Özellikle referans tiplerinin bağımsız kopyalarını (sığ veya derin) oluşturmak istendiğinde kullanışlıdır.
public class Adres
{
public string Sokak { get; set; }
public string Sehir { get; set; }
// Normal yapıcı
public Adres(string sokak, string sehir)
{
Sokak = sokak;
Sehir = sehir;
}
// Kopya Yapıcı
public Adres(Adres kaynakAdres)
{
Console.WriteLine("Adres kopya yapıcısı çalıştı.");
// Değer tiplerini veya immutable referans tiplerini (string) kopyala
this.Sokak = kaynakAdres.Sokak;
this.Sehir = kaynakAdres.Sehir;
// Dikkat: Eğer Adres içinde başka referans tipleri olsaydı,
// bu sığ (shallow) kopya olurdu. Derin (deep) kopya için
// iç içe nesnelerin de kopyalanması gerekirdi.
}
}
// Kullanım:
Adres adres1 = new Adres("Atatürk Cad.", "Ankara");
Adres adres2 = new Adres(adres1); // Kopya yapıcıyı çağır
adres2.Sokak = "İnönü Bulvarı"; // adres2'nin sokağını değiştir
Console.WriteLine(adres1.Sokak); // Atatürk Cad. (Orijinal değişmedi)
Console.WriteLine(adres2.Sokak); // İnönü Bulvarı
2.5. Özel Yapıcı (Private Constructor)

Yapıcının erişim belirleyicisi private olarak ayarlanırsa, o sınıftan doğrudan new ile nesne oluşturulması engellenir.
Kullanım Alanları:
Singleton Deseni: Bir sınıftan yalnızca tek bir örnek oluşturulmasını garanti etmek için kullanılır. Nesne örneği sınıfın içinde özel bir statik alan olarak tutulur ve public statik bir metot veya özellik aracılığıyla dışarıya verilir.
Sadece Statik Üyeler İçeren Sınıflar: System.Math veya System.Console gibi, sadece statik metotlar ve özellikler içeren ve örneklenmesi amaçlanmayan sınıflarda, örneklenmeyi tamamen engellemek için private (veya static) bir yapıcı tanımlanabilir.
public class Singleton
{
private static Singleton? _instance = null;
private static readonly object _lock = new object();
// Private yapıcı - dışarıdan new Singleton() yapılamaz
private Singleton()
{
Console.WriteLine("Singleton örneği oluşturuldu.");
}
// Örneğe erişmek için public statik özellik
public static Singleton Instance
{
get
{
// Thread-safe kontrol (double-checked locking)
if (_instance == null)
{
lock (_lock)
{
if (_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
}
public void MesajVer() => Console.WriteLine("Singleton çalışıyor.");
}
// Kullanım:
// Singleton s1 = new Singleton(); // Hata! Private yapıcı.
Singleton s1 = Singleton.Instance; // İlk erişimde nesne oluşturulur
Singleton s2 = Singleton.Instance; // Aynı örnek döndürülür
Console.WriteLine(s1 == s2); // True (Aynı örnek)
s1.MesajVer();
2.6. Statik Yapıcı (Static Constructor)

static anahtar kelimesiyle tanımlanır, erişim belirleyicisi olmaz ve parametre alamaz.
Bir sınıfın statik üyelerini başlatmak için kullanılır.
CLR tarafından, o sınıfa ilk kez erişildiğinde (ilk nesne oluşturulduğunda veya ilk statik üyeye erişildiğinde) otomatik olarak ve sadece bir kez çağrılır. Çağrılma zamanı tam olarak garanti edilmez, ancak ilk kullanımdan öncedir.
Özellikle statik alanlara karmaşık başlangıç değerleri atamak veya statik başlatma için gereken diğer işlemleri yapmak amacıyla kullanılır.
public class VeritabaniBaglantisi
{
private static readonly string _baglantiStringi;
public static int MaxHavuzBoyutu { get; private set; }
// Statik Yapıcı
static VeritabaniBaglantisi()
{
Console.WriteLine("VeritabaniBaglantisi statik yapıcısı çalıştı!");
// Konfigürasyon dosyasından veya ortam değişkenlerinden oku varsayalım
_baglantiStringi = AyarlariOku("DbConnectionString");
MaxHavuzBoyutu = Convert.ToInt32(AyarlariOku("DbMaxPoolSize") ?? "10");
}
// Örnek yapıcı
public VeritabaniBaglantisi() { /* ... / }
public static string BaglantiStringiAl() => _baglantiStringi;
// Varsayımsal ayar okuma metodu
private static string? AyarlariOku(string key) {
// ... dosya okuma veya ortam değişkeni okuma mantığı ...
if (key == "DbConnectionString") return "Server=.;Database=TestDB;Trusted_Connection=True;";
if (key == "DbMaxPoolSize") return "50";
return null;
}
}
// Kullanım
Console.WriteLine("Uygulama Başladı.");
// İlk statik üyeye erişim (statik yapıcıyı tetikler)
Console.WriteLine($"Maks Havuz: {VeritabaniBaglantisi.MaxHavuzBoyutu}");
Console.WriteLine($"Bağlantı: {VeritabaniBaglantisi.BaglantiStringiAl()}");
VeritabaniBaglantisi baglanti1 = new VeritabaniBaglantisi(); // Statik yapıcı tekrar çalışmaz
VeritabaniBaglantisi baglanti2 = new VeritabaniBaglantisi(); // Statik yapıcı tekrar çalışmaz
Console.WriteLine("Uygulama Bitti.");
/
Örnek Çıktı:
Uygulama Başladı.
VeritabaniBaglantisi statik yapıcısı çalıştı!
Maks Havuz: 50
Bağlantı: Server=.;Database=TestDB;Trusted_Connection=True;
Uygulama Bitti.
*/
Bölüm 3: Yapıcı Zincirleme (Constructor Chaining)

Bir sınıfın birden fazla yapıcısı olduğunda, kod tekrarını önlemek için bir yapıcının aynı sınıftaki başka bir yapıcıyı veya temel (üst) sınıftaki bir yapıcıyı çağırması yaygın bir pratiktir.

3.1. Aynı Sınıfta Zincirleme (this(…))

Bir yapıcı, kendi sınıfındaki başka bir (genellikle daha fazla parametre alan) yapıcıyı çağırmak için this anahtar kelimesini ve ardından parantez içinde uygun argümanları kullanır. this(…) çağrısı, yapıcı tanımındaki parametre listesinden sonra, gövde { başlamadan önce : ile belirtilir. Çağrılan yapıcı, mevcut yapıcıdan önce çalışır.

Örnek (Yukarıdaki Kitap sınıfından):

public class Kitap
{
// ... Alanlar ...
// Parametresiz yapıcı, Üç parametreliyi çağırıyor
public Kitap() : this("Bilinmiyor", "Bilinmiyor", 0)
{
Console.WriteLine("Parametresiz Kitap yapıcısı gövdesi.");
// this(...) çağrısı bittikten SONRA burası çalışır
}
// İki parametreli yapıcı, Üç parametreliyi çağırıyor
public Kitap(string baslik, string yazar) : this(baslik, yazar, -1)
{
Console.WriteLine("İki parametreli Kitap yapıcısı gövdesi.");
}
// Üç parametreli ana yapıcı
public Kitap(string baslik, string yazar, int sayfaSayisi)
{
Console.WriteLine("Üç parametreli Kitap yapıcısı gövdesi.");
// Alanlara atamalar burada yapılır
Baslik = baslik;
Yazar = yazar;
SayfaSayisi = sayfaSayisi > 0 ? sayfaSayisi : 0;
}
// ... Özellikler ...
}
// new Kitap("Suç ve Ceza", "Dostoyevski"); çağrıldığında:
// 1. İki parametreli yapıcıya girer.
// 2. ':' nedeniyle this("Suç ve Ceza", "Dostoyevski", -1) çağrılır.
// 3. Üç parametreli yapıcı çalışır (Konsola "Üç parametreli..." yazar, atamaları yapar).
// 4. Kontrol iki parametreli yapıcının gövdesine döner (Konsola "İki parametreli..." yazar).
Bu, ortak başlatma mantığını tek bir ana yapıcıda toplamayı sağlar.

3.2. Üst Sınıf Yapıcısını Çağırma (base(…))

Kalıtım (inheritance) kullanıldığında, bir alt sınıfın (derived class) yapıcısı, üst sınıfın (base class) yapıcısını çağırmak için base anahtar kelimesini kullanır. Bu, üst sınıfın kendi alanlarını ve başlangıç durumunu doğru bir şekilde ayarlamasını sağlar.

Eğer alt sınıf yapıcısında açıkça bir base(…) çağrısı yapılmazsa, derleyici örtük olarak üst sınıfın parametresiz yapıcısını (base()) çağırmaya çalışır. Eğer üst sınıfın erişilebilir ( public veya protected) parametresiz bir yapıcısı yoksa, derleme hatası alınır.
base(…) çağrısı da this(…) gibi :’dan sonra ve yapıcı gövdesinden önce belirtilir.
this(…) ve base(…) aynı yapıcıda birlikte kullanılamaz.
Örnek:

public class Arac
{
public string Marka { get; }
public int Yil { get; }
// Üst sınıf yapıcısı
public Arac(string marka, int yil)
{
Console.WriteLine("Arac yapıcısı çalıştı.");
Marka = marka;
Yil = yil;
}
}
public class Otomobil : Arac // Arac'tan miras alıyor
{
public int KapiSayisi { get; }
// Alt sınıf yapıcısı, üst sınıf yapıcısını base() ile çağırıyor
public Otomobil(string marka, int yil, int kapiSayisi) : base(marka, yil) // base(marka, yil) çağrısı
{
Console.WriteLine("Otomobil yapıcısı çalıştı.");
KapiSayisi = kapiSayisi;
// base(...) çağrısı bu gövdeden ÖNCE çalışır.
}
}
// Kullanım
Otomobil oto = new Otomobil("Ford", 2022, 4);
// Çıktı:
// Arac yapıcısı çalıştı.
// Otomobil yapıcısı çalıştı.
base() çağrısı, kalıtım hiyerarşisinde nesnelerin doğru bir şekilde başlatılmasını garanti eder.

Bölüm 4: Nesne Başlatıcılar (Object Initializers)

C# 3.0 ile gelen nesne başlatıcılar, new ifadesinden sonra, nesnenin erişilebilir (public) alanlarını veya özelliklerini yapıcı metot çağrıldıktan hemen sonra daha kısa bir söz dizimi ile ayarlamanın bir yoludur.

Sözdizimi:

SinifAdi nesne = new SinifAdi([yapıcı_argümanları])
{
OzellikAdi1 = deger1,
OzellikAdi2 = deger2,
// AlanAdi = deger3 // Public alanlar da atanabilir (önerilmez)
};
Nesne new ile oluşturulur ve uygun yapıcı metot çağrılır.
Ardından, kıvırcık parantez {} içindeki atamalar sırayla çalıştırılır.
Bu, özellikle çok sayıda özelliği olan nesneleri veya parametresiz yapıcıyla oluşturulup sonra özellikleri ayarlanan nesneleri başlatmak için kodu daha okunabilir hale getirebilir.
Örnek:

public class Calisan
{
public int Id { get; set; }
public string AdSoyad { get; set; }
public string Departman { get; set; }
public decimal Maas { get; set; }
// Parametresiz yapıcı varsayılan olarak var (veya açıkça eklenebilir)
}
// Kullanım
Calisan calisan1 = new Calisan
{
Id = 101,
AdSoyad = "Deniz Yücel",
Departman = "IT",
Maas = 15000m
};
// Yapıcı + Başlatıcı
public class Nokta3D
{
public int X { get; set; }
public int Y { get; set; }
public int Z { get; set; }
public Nokta3D(int x, int y) { X = x; Y = y; Z = 0; } // Z'yi varsayılan 0 yapar
}
Nokta3D p = new Nokta3D(10, 20) { Z = 30 }; // Önce yapıcı çalışır (X=10, Y=20, Z=0),
// sonra başlatıcı çalışır (Z=30 olur).
Nesne başlatıcılar, yapıcı metotların yerini almaz, onlarla birlikte çalışır. Önce yapıcı çalışır, sonra başlatıcıdaki atamalar yapılır. init erişimcisine sahip özellikler sadece yapıcıda veya nesne başlatıcıda atanabilir.

Bölüm 5: Sonuç — Nesne Oluşturmanın Anahtarı

Yapıcı Metotlar (Constructors), C#’ta nesnelerin hayata geldiği ve başlangıç durumlarının ayarlandığı kritik mekanizmalardır. Sınıfla aynı isme sahip olmaları ve geri dönüş türlerinin olmamasıyla diğer metotlardan ayrılırlar. Varsayılan (derleyici tarafından oluşturulan), parametreli (en yaygın), kopya (desen) ve statik (sınıf bazlı başlatma) gibi farklı türleri, çeşitli başlatma senaryolarına çözüm sunar.

Yapıcı aşırı yüklemesi, nesneleri farklı veri setleriyle oluşturma esnekliği sağlarken, yapıcı zincirlemesi (this() ve base()), kod tekrarını önleyerek ve kalıtım hiyerarşisinde doğru başlatmayı garanti ederek kodun bakımını kolaylaştırır. Nesne başlatıcılar ise, özellikle çok sayıda özelliği olan nesneler için, yapıcı çağrısından sonra özellikleri ayarlamanın okunabilir bir yolunu sunar.

Özel yapıcılar Singleton gibi tasarım desenlerini mümkün kılar. Erişim belirleyicileri yapıcıların nereden çağrılabileceğini kontrol ederken, statik yapıcılar sınıfın ilk kullanımından önce gerekli statik başlatmaları gerçekleştirir.

Sonuç olarak, yapıcı metotları anlamak ve doğru bir şekilde kullanmak, C#’ta sağlam, tutarlı ve iyi tasarlanmış sınıflar oluşturmanın temelidir. Nesnelerin yaşam döngüsünün bu ilk ve en önemli adımına hakim olmak, etkili Nesne Yönelimli Programlama pratiği için vazgeçilmezdir.

Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Kişisel WebSite
Abdulkadir Güngör - Özgeçmiş
Github
Github
Linkedin