Ahmet Balaman LogoAhmet Balaman

C# Constructor: Nesne Fabrikasının Gizli Kahramanı

personAhmet Balaman
calendar_today
C#OOPConstructor.NETProgramlama Temelleri

Constructor: Nesne Doğduğu An Ne Olur?

Bir önceki yazıda Class ve Object kavramlarını öğrendik. Nesneler oluşturduk, property'lerine değer atadık. Ama her seferinde şunu yapmak zorunda kaldık:

Araba araba1 = new Araba();
araba1.Marka = "Toyota";
araba1.Model = "Corolla";
araba1.Yil = 2024;
araba1.Renk = "Beyaz";

4 satır kod, sadece bir araba oluşturmak için. Ya 100 araba oluşturacaksak? Ya bazı property'leri atamayı unutursak?

İşte Constructor tam bu sorunu çözüyor.

Constructor Nedir?

Constructor (Yapıcı Metod), nesne oluşturulduğu anda otomatik olarak çağrılan özel bir metoddur. Adı, class adıyla aynı olmak zorundadır ve return type'ı yoktur.

public class Araba
{
    public string Marka { get; set; }
    public string Model { get; set; }
    public int Yil { get; set; }
    public string Renk { get; set; }
    
    // Constructor
    public Araba(string marka, string model, int yil, string renk)
    {
        Marka = marka;
        Model = model;
        Yil = yil;
        Renk = renk;
        Console.WriteLine($"🚗 Yeni {marka} {model} üretildi!");
    }
}

// Kullanım - Tek satır!
Araba araba1 = new Araba("Toyota", "Corolla", 2024, "Beyaz");

Gördünüz mü? 4 satır yerine 1 satır. Ve en güzeli: Artık hiçbir property'yi atlamak mümkün değil çünkü constructor zorunlu kılıyor.

Default Constructor: Sessiz Kahraman

Eğer hiç constructor yazmazsanız, C# sizin için gizlice bir tane oluşturur. Buna default constructor (varsayılan yapıcı) denir.

public class Kutu
{
    public int Genislik { get; set; }
    public int Yukseklik { get; set; }
}

// C# arka planda şunu oluşturur:
// public Kutu() { }

Kutu kutu1 = new Kutu();  // Bu çalışır
kutu1.Genislik = 10;
kutu1.Yukseklik = 20;

Ama dikkat! Siz kendi constructor'ınızı yazarsanız, default constructor kaybolur:

public class Kutu
{
    public int Genislik { get; set; }
    public int Yukseklik { get; set; }
    
    public Kutu(int genislik, int yukseklik)
    {
        Genislik = genislik;
        Yukseklik = yukseklik;
    }
}

Kutu kutu1 = new Kutu();  // ❌ HATA! Parametresiz constructor yok
Kutu kutu2 = new Kutu(10, 20);  // ✅ Çalışır

Constructor Overloading: Seçenekler Sunmak

Bazen kullanıcıya farklı seçenekler sunmak istersiniz. "İstersen sadece marka ver, istersen hepsini ver." Buna constructor overloading denir.

public class Oyuncu
{
    public string Ad { get; set; }
    public int Seviye { get; set; }
    public int Can { get; set; }
    public string Sinif { get; set; }
    
    // Constructor 1: Sadece isim ile
    public Oyuncu(string ad)
    {
        Ad = ad;
        Seviye = 1;      // Varsayılan değerler
        Can = 100;
        Sinif = "Savaşçı";
    }
    
    // Constructor 2: İsim ve sınıf ile
    public Oyuncu(string ad, string sinif)
    {
        Ad = ad;
        Sinif = sinif;
        Seviye = 1;
        Can = 100;
    }
    
    // Constructor 3: Tam donanımlı
    public Oyuncu(string ad, string sinif, int seviye, int can)
    {
        Ad = ad;
        Sinif = sinif;
        Seviye = seviye;
        Can = can;
    }
    
    public void BilgiGoster()
    {
        Console.WriteLine($"⚔️ {Ad} | Sınıf: {Sinif} | Seviye: {Seviye} | Can: {Can}");
    }
}

Şimdi kullanıcı istediği gibi nesne oluşturabilir:

Oyuncu oyuncu1 = new Oyuncu("Ahmet");
Oyuncu oyuncu2 = new Oyuncu("Elif", "Büyücü");
Oyuncu oyuncu3 = new Oyuncu("Mehmet", "Okçu", 50, 500);

oyuncu1.BilgiGoster();  // ⚔️ Ahmet | Sınıf: Savaşçı | Seviye: 1 | Can: 100
oyuncu2.BilgiGoster();  // ⚔️ Elif | Sınıf: Büyücü | Seviye: 1 | Can: 100
oyuncu3.BilgiGoster();  // ⚔️ Mehmet | Sınıf: Okçu | Seviye: 50 | Can: 500

this() ile Constructor Zincirleme

Constructor'lar arasında kod tekrarı oluyor fark ettiniz mi? Her seferinde aynı atamaları yapıyoruz. this() ile bir constructor'dan diğerini çağırabiliriz:

public class Oyuncu
{
    public string Ad { get; set; }
    public int Seviye { get; set; }
    public int Can { get; set; }
    public string Sinif { get; set; }
    
    // Ana constructor - Tüm parametreler
    public Oyuncu(string ad, string sinif, int seviye, int can)
    {
        Ad = ad;
        Sinif = sinif;
        Seviye = seviye;
        Can = can;
        Console.WriteLine($"✨ {ad} oyuna katıldı!");
    }
    
    // Sadece isim - Ana constructor'ı çağır
    public Oyuncu(string ad) : this(ad, "Savaşçı", 1, 100)
    {
        // Ekstra kod yazılabilir
    }
    
    // İsim ve sınıf - Ana constructor'ı çağır
    public Oyuncu(string ad, string sinif) : this(ad, sinif, 1, 100)
    {
    }
}

: this(...) syntax'ı, önce o constructor'ı çalıştır, sonra bu constructor'ın gövdesini çalıştır demek.

Optional Parameters: Modern Yaklaşım

C#'ın güzel özelliklerinden biri: Opsiyonel parametreler. Constructor overloading yerine tek constructor ile aynı esnekliği sağlayabilirsiniz.

public class Urun
{
    public string Ad { get; set; }
    public decimal Fiyat { get; set; }
    public int Stok { get; set; }
    public string Kategori { get; set; }
    public bool AktifMi { get; set; }
    
    public Urun(
        string ad, 
        decimal fiyat, 
        int stok = 0,                    // Varsayılan: 0
        string kategori = "Genel",       // Varsayılan: "Genel"
        bool aktifMi = true)             // Varsayılan: true
    {
        Ad = ad;
        Fiyat = fiyat;
        Stok = stok;
        Kategori = kategori;
        AktifMi = aktifMi;
    }
}

// Farklı kullanım şekilleri
Urun urun1 = new Urun("Laptop", 25000);
Urun urun2 = new Urun("Mouse", 500, 100);
Urun urun3 = new Urun("Klavye", 800, 50, "Elektronik");
Urun urun4 = new Urun("Monitör", 8000, kategori: "Elektronik");  // Named parameter

Named parameter'lar sayesinde ortadaki parametreleri atlayabilirsiniz. Çok kullanışlı!

Gerçek Dünya Örneği: E-Ticaret Sipariş Sistemi

Şimdi öğrendiklerimizi birleştirelim. Gerçek bir e-ticaret sisteminde sipariş oluşturmayı düşünün:

public class Siparis
{
    public string SiparisNo { get; private set; }
    public string MusteriAdi { get; set; }
    public List<string> Urunler { get; set; }
    public decimal ToplamTutar { get; set; }
    public DateTime OlusturmaTarihi { get; private set; }
    public string Durum { get; private set; }
    
    // Private constructor - Dışarıdan doğrudan oluşturulamaz
    private Siparis()
    {
        SiparisNo = GenerateSiparisNo();
        OlusturmaTarihi = DateTime.Now;
        Durum = "Beklemede";
        Urunler = new List<string>();
    }
    
    // Public constructor - Standart sipariş
    public Siparis(string musteriAdi) : this()
    {
        MusteriAdi = musteriAdi;
    }
    
    // Tam donanımlı sipariş
    public Siparis(string musteriAdi, List<string> urunler, decimal toplamTutar) : this()
    {
        MusteriAdi = musteriAdi;
        Urunler = urunler;
        ToplamTutar = toplamTutar;
    }
    
    private string GenerateSiparisNo()
    {
        return $"SIP-{DateTime.Now:yyyyMMdd}-{new Random().Next(1000, 9999)}";
    }
    
    public void UrunEkle(string urunAdi, decimal fiyat)
    {
        Urunler.Add(urunAdi);
        ToplamTutar += fiyat;
        Console.WriteLine($"✅ '{urunAdi}' sepete eklendi. Toplam: {ToplamTutar:C}");
    }
    
    public void SiparisOzeti()
    {
        Console.WriteLine("\n" + new string('=', 40));
        Console.WriteLine($"📦 SİPARİŞ BİLGİLERİ");
        Console.WriteLine(new string('=', 40));
        Console.WriteLine($"Sipariş No: {SiparisNo}");
        Console.WriteLine($"Müşteri: {MusteriAdi}");
        Console.WriteLine($"Tarih: {OlusturmaTarihi:dd/MM/yyyy HH:mm}");
        Console.WriteLine($"Durum: {Durum}");
        Console.WriteLine("\nÜrünler:");
        foreach (var urun in Urunler)
        {
            Console.WriteLine($"  • {urun}");
        }
        Console.WriteLine($"\n💰 TOPLAM: {ToplamTutar:C}");
        Console.WriteLine(new string('=', 40));
    }
}

Kullanım:

// Boş sipariş başlat
Siparis siparis1 = new Siparis("Ahmet Yılmaz");
siparis1.UrunEkle("iPhone 15", 64999);
siparis1.UrunEkle("AirPods Pro", 9999);
siparis1.UrunEkle("MagSafe Şarj", 1499);
siparis1.SiparisOzeti();

// Hazır ürün listesiyle sipariş
var urunler = new List<string> { "MacBook Pro", "Magic Mouse", "USB-C Hub" };
Siparis siparis2 = new Siparis("Elif Demir", urunler, 85000);
siparis2.SiparisOzeti();

Çıktı:

'iPhone 15' sepete eklendi. Toplam: ₺64.999,00'AirPods Pro' sepete eklendi. Toplam: ₺74.998,00'MagSafe Şarj' sepete eklendi. Toplam: ₺76.497,00

========================================
📦 SİPARİŞ BİLGİLERİ
========================================
Sipariş No: SIP-20260203-4721
Müşteri: Ahmet Yılmaz
Tarih: 03/02/2026 14:30
Durum: Beklemede

Ürünler:
  • iPhone 15AirPods ProMagSafe Şarj

💰 TOPLAM: ₺76.497,00
========================================

Static Constructor: Sınıf Yüklenirken Çalışır

Bazen sınıf ilk kez kullanıldığında bir şeyler yapmak istersiniz. Static constructor tam bunun için:

public class Veritabani
{
    public static string ConnectionString { get; private set; }
    public static bool Baglandi { get; private set; }
    
    // Static constructor - Sınıf ilk kullanıldığında bir kez çalışır
    static Veritabani()
    {
        Console.WriteLine("🔌 Veritabanı bağlantısı kuruluyor...");
        ConnectionString = "Server=localhost;Database=MyApp;";
        Baglandi = true;
        Console.WriteLine("✅ Bağlantı hazır!");
    }
    
    public static void SorguCalistir(string sql)
    {
        if (Baglandi)
        {
            Console.WriteLine($"📊 Sorgu çalıştırılıyor: {sql}");
        }
    }
}

// İlk kullanımda static constructor çalışır
Veritabani.SorguCalistir("SELECT * FROM Users");
Veritabani.SorguCalistir("SELECT * FROM Products");

// Çıktı:
// 🔌 Veritabanı bağlantısı kuruluyor...
// ✅ Bağlantı hazır!
// 📊 Sorgu çalıştırılıyor: SELECT * FROM Users
// 📊 Sorgu çalıştırılıyor: SELECT * FROM Products

Static constructor:

  • Parametre alamaz
  • Access modifier'ı olmaz
  • Sadece bir kez çalışır
  • Ne zaman çalışacağını biz kontrol edemeyiz (CLR karar verir)

Constructor'da Validation: Sağlamlık Önemli

Constructor, nesne oluşturulurken gelen verileri doğrulamak için mükemmel bir yer:

public class Email
{
    public string Adres { get; private set; }
    public string Domain { get; private set; }
    
    public Email(string adres)
    {
        if (string.IsNullOrWhiteSpace(adres))
            throw new ArgumentException("Email adresi boş olamaz!");
        
        if (!adres.Contains("@"))
            throw new ArgumentException("Geçersiz email formatı!");
        
        if (adres.Length < 5)
            throw new ArgumentException("Email adresi çok kısa!");
        
        Adres = adres.ToLower().Trim();
        Domain = Adres.Split('@')[1];
        
        Console.WriteLine($"✅ Email oluşturuldu: {Adres}");
    }
}

try
{
    Email email1 = new Email("[email protected]");  // ✅ Çalışır
    Email email2 = new Email("gecersiz-email");   // ❌ Hata fırlatır
}
catch (ArgumentException ex)
{
    Console.WriteLine($"❌ Hata: {ex.Message}");
}

Özet: Constructor Çeşitleri

Tür Açıklama Örnek
Default Parametresiz, C# otomatik oluşturur public Sinif() {}
Parametreli Değer alır public Sinif(int x) {}
Overloaded Birden fazla constructor Farklı parametre kombinasyonları
Chained Diğer constructor'ı çağırır : this(...)
Static Sınıf yüklenirken çalışır static Sinif() {}
Private Dışarıdan erişilemez Factory pattern için

Sonraki Adım: Access Modifiers

Constructor'lar sayesinde nesnelerimizi daha güvenli ve tutarlı bir şekilde oluşturabiliyoruz.

Bir sonraki yazıda Access Modifiers (Erişim Belirleyiciler) konusunu işleyeceğiz. public, private, protected ne demek? Neden her şeyi public yapmak kötü bir fikir? Getter ve Setter'lar ne işe yarıyor?

Temiz kod yazmaya devam! 🚀


Bu yazı, C# ile OOP serisinin üçüncü yazısıdır. Bir önceki yazıda Class ve Object kavramlarını, bir sonraki yazıda Access Modifiers konusunu ele alacağız.

Yorumlar