C# İle Delegeler Kullanarak Olay Yönetimi Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Bu rehberdeki kod örneklerini çalıştırmak için modern bir C# geliştirme ortamına ihtiyacınız vardır. 2026 standartları gereği .NET 8 veya üzeri sürümleri kullanmanız önerilir.

  • IDE: Visual Studio 2022 veya VS Code (C# Dev Kit eklentisi ile).
  • SDK: .NET 8.0 SDK veya daha güncel sürüm.
  • Bilgi Seviyesi: Sınıflar, metotlar ve temel OOP prensipleri hakkında bilgi sahibi olmanız yeterlidir.

Projenizi oluşturmak için terminal ekranında dotnet new console -n OlayYonetimiProjesi komutunu kullanarak başlangıç yapabilirsiniz.

Delege (Delegate) Nedir ve Nasıl Tanımlanır?

Delege, belirli bir parametre listesine ve dönüş türüne sahip metotlara referans tutan bir türdür. Olay yönetiminin temel taşıdır çünkü bir olayın tetiklendiğinde hangi metodun çalışacağını "adresler".

// Bir delege tanımlıyoruz
public delegate void IslemTamamlandiHandler(string mesaj);

public class Islemci {
    public void Calistir(IslemTamamlandiHandler callback) {
        // İşlemler yapıldıktan sonra callback çağrılır
        callback("İşlem başarıyla tamamlandı.");
    }
}

Burada IslemTamamlandiHandler, string parametre alan ve geriye değer döndürmeyen her türlü metodu temsil edebilir. Bu yapı, metodun kendisini değil, metodun imzasını taşır.

Adım Adım Olay (Event) Tanımlama ve Tetikleme

Olaylar, delegelerin etrafına sarılmış birer koruma kalkanıdır. Doğrudan delege kullanmak yerine event anahtar kelimesini kullanmak, dışarıdan sadece abone olunmasını (subscribe) sağlar, ancak olayın tetiklenmesini (invoke) sadece tanımlandığı sınıfın içinde tutar.

public class StokYonetimi {
    // Delege tanımı
    public delegate void StokAzaldiHandler(string urunAdi, int kalanAdet);
    
    // Olay tanımı
    public event StokAzaldiHandler StokAzaldi;

    public void UrunSat(string urun, int adet) {
        // Satış işlemleri burada yapılır...
        
        // Olayı tetikle
        StokAzaldi?.Invoke(urun, adet);
    }
}

?.Invoke kullanımı, olaya abone olan kimse yoksa (null kontrolü) uygulamanın hata vermesini engeller. Bu, 2026 yılı C# standartlarında en güvenli tetikleme yöntemidir.

Olaylara Abone Olma ve Dinleme

Oluşturduğunuz olayları dinlemek için += operatörünü kullanırsınız. Bir sınıfın ürettiği bir olaya dışarıdan metot bağlamak, olay odaklı programlamanın özüdür.

class Program {
    static void Main() {
        StokYonetimi stok = new StokYonetimi();
        
        // Olayı dinlemeye başla
        stok.StokAzaldi += StokUyariMetodu;
        
        stok.UrunSat("Laptop", 2);
    }

    static void StokUyariMetodu(string urun, int adet) {
        Console.WriteLine($"Uyarı: {urun} stoğu {adet} adede düştü!");
    }
}

Bu yapıda StokUyariMetodu, StokAzaldi olayı gerçekleştiğinde otomatik olarak çağrılır. Abone olmayı bırakmak isterseniz -= operatörünü kullanmanız yeterlidir.

Olay Yönetiminde Best Practices (En İyi Pratikler)

Olay yönetimi yaparken bellek sızıntılarını (memory leak) önlemek ve kodun okunabilirliğini artırmak için bazı standartlara uymalısınız. Özellikle EventHandler kullanımı C# dünyasında bir standarttır.

Yöntem Avantajı Dezavantajı
Custom Delegate Tam kontrol sağlar. Daha fazla kod yazımı gerektirir.
EventHandler Standarttır, okunabilirlik yüksektir. Özel veri sınıfları gerektirir.

Aşağıdaki örnekte standart EventHandler kullanımı gösterilmiştir:

public class SiparisEventArgs : EventArgs {
    public string SiparisNo { get; set; }
}

public class SiparisSistemi {
    public event EventHandler SiparisOlusturuldu;

    public void SiparisVer(string no) {
        SiparisOlusturuldu?.Invoke(this, new SiparisEventArgs { SiparisNo = no });
    }
}

Kritik Güvenlik Uyarısı: Olaylara abone olan nesnelerin yaşam döngülerini yönetin. Bir nesne yok edilmeden önce abone olduğu olaydan -= ile ayrılmazsa, "Garbage Collector" nesneyi bellekten temizleyemez ve bellek sızıntısı oluşur.

Yaygın Hatalar ve Debug İpuçları

Yazılımcıların olay yönetiminde yaptığı en yaygın hata, olayı tetikleyen sınıfın dışından doğrudan Invoke etmeye çalışmaktır. event anahtar kelimesi, bu yetkiyi kısıtlayarak kapsülleme (encapsulation) sağlar.

Debug İpuçları:

  • Olayın tetiklenip tetiklenmediğini anlamak için Invoke satırına breakpoint koyun.
  • Abone listesini kontrol etmek için GetInvocationList() metodunu kullanabilirsiniz.
  • Çoklu aboneliklerde (multicast delegate) bir metodun hata vermesi, diğerlerinin çalışmasını durdurabilir; bu yüzden her aboneliği ayrı bir try-catch bloğu ile sarmalamayı düşünün.
  • Sıkça Sorulan Sorular

    Delegeler ile Olaylar arasındaki temel fark nedir?

    Delege bir tür tanımıdır; olay ise bu türün kapsüllenmiş, sadece abone olunabilir ve tetiklenebilir bir örneğidir. Olaylar, delegelerin güvenli bir arayüzle sunulmuş halidir.

    Bir olaya birden fazla metot bağlayabilir miyim?

    Evet, C# delegeleri "multicast" (çoklu yayın) özelliğine sahiptir. += operatörü ile istediğiniz kadar metodu aynı olaya bağlayabilirsiniz.

    Olayları thread-safe (iş parçacığı güvenli) nasıl yaparım?

    Olay tetikleme sırasında lock mekanizması kullanarak veya Interlocked.CompareExchange gibi atomik işlemlerle tetikleme anında abonelerin değişmesini engelleyebilirsiniz.

    EventHandler neden öneriliyor?

    Microsoft tarafından standartlaştırılmıştır. Tüm .NET kütüphaneleri bu yapıyı kullandığı için diğer geliştiricilerin kodunuzu anlaması kolaylaşır.

    Lambda ifadeleri olaylarda kullanılabilir mi?

    Evet, stok.StokAzaldi += (u, a) => Console.WriteLine(u); şeklinde kısa ve hızlı abonelikler oluşturabilirsiniz.

    Asenkron Olay Yönetimi ve Task Tabanlı Tetikleme

    Geleneksel olay yönetimi senkron bir yapıya sahiptir; yani olay tetiklendiğinde, ona abone olan tüm metotlar sırayla ve ana iş parçacığını (main thread) bloke ederek çalışır. Eğer olaylardan biri ağır bir veritabanı sorgusu veya dosya okuma işlemi yapıyorsa, uygulamanızın arayüzü donabilir. Modern C# uygulamalarında bu sorunu aşmak için async/await yapısını olaylarla entegre etmeliyiz.

    Olayları asenkron hale getirirken dikkat edilmesi gereken en önemli nokta, olay tetikleyicinin (publisher) asenkron metotları bekleyip beklemeyeceğine karar vermektir. Standart EventHandler yapısı void döndürdüğü için asenkron işlemler için özel bir yaklaşım gerektirir.

    public class AsyncEventPublisher
    {
        // Asenkron olay için özel bir delege tanımı
        public event Func OnDataProcessed;
    
        public async Task ProcessDataAsync(string data)
        {
            Console.WriteLine("İşlem başlatılıyor...");
            
            if (OnDataProcessed != null)
            {
                // Tüm aboneleri asenkron olarak çağır ve tamamlanmalarını bekle
                var invocationList = OnDataProcessed.GetInvocationList();
                foreach (Func handler in invocationList)
                {
                    await handler(data);
                }
            }
            
            Console.WriteLine("Tüm işlemler tamamlandı.");
        }
    }
    

    Olay Yönetiminde Performans Optimizasyonu

    Olaylar, özellikle çok sık tetiklenen (high-frequency) sistemlerde (örneğin bir sensör verisi veya yüksek trafikli ağ paketi izleme) bellek sızıntılarına ve performans darboğazlarına yol açabilir. Performansı optimize etmek için şu stratejileri uygulayabilirsiniz:

    • Bellek Sızıntılarını Önleme: Abone olan nesneler yaşam döngülerini tamamladığında, olaydan aboneliklerini kaldırmayı (unsubscribe) unutmayın. Aksi takdirde, yayıncı nesne aboneleri referans tutmaya devam edeceği için Garbage Collector (GC) bu nesneleri bellekten temizleyemez.
    • Weak Event Pattern: Eğer abonelerin ömrünü kontrol edemiyorsanız, WeakEventManager kullanarak zayıf referanslar üzerinden olay yönetimi yapın.
    • Gereksiz Tetiklemeleri Filtreleme: Olay tetiklenmeden önce, gerçekten bir abonenin olup olmadığını kontrol edin (if (event != null)) ve eğer olay verisi kritik değilse, tetikleme sıklığını bir Throttling mekanizması ile sınırlayın.
    // Bellek sızıntısını önlemek için abonelik iptali
    public void Dispose()
    {
        // Olaydan aboneliği kaldır
        _publisher.OnDataProcessed -= HandleData;
    }
    

    Olay Tabanlı Sistemlerde Birim Test (Unit Testing)

    Olayların test edilmesi, genellikle bir olayın tetiklenip tetiklenmediğini veya doğru parametrelerle tetiklenip tetiklenmediğini doğrulamayı içerir. Bu amaçla Moq gibi kütüphaneler kullanarak olayları "mock" edebilir veya basit bir "flag" (bayrak) mekanizması ile testlerinizi yazabilirsiniz.

    Test Senaryosu Doğrulama Yöntemi
    Olay tetiklendi mi? Boolean bir değişkeni true yaparak kontrol edin.
    Doğru veri gönderildi mi? Olay argümanlarını (EventArgs) bir değişkene atayarak içerik kontrolü yapın.
    Abonelik iptali çalışıyor mu? GC.Collect() sonrası nesnenin bellekten silinip silinmediğini kontrol edin.

    Birim testlerinizde, olay tetiklendiğinde çalışan metotların yan etkilerini (side effects) izole etmek için Dependency Injection prensiplerini kullanarak olay işleyicilerini arayüzler (interface) üzerinden yönetmeniz test edilebilirliği ciddi oranda artıracaktır.

    Sonuç

    C# ile delegeler kullanarak olay yönetimi yapmak, uygulamanızın parçalarını birbirinden bağımsız hale getirerek sürdürülebilir bir mimari kurmanıza olanak tanır. Olaylar, özellikle kullanıcı arayüzü (UI) güncellemeleri, veritabanı loglama işlemleri veya arka plan görevlerinin tamamlanması gibi senaryolarda hayat kurtarıcıdır.

    Kod Güvenliği Sorumluluk Reddi: Bu makalede paylaşılan kod örnekleri eğitim amaçlıdır. Üretim ortamında (production) kullanırken, özellikle dış girdilerin olay parametrelerine dahil olduğu durumlarda veri doğrulama ve tip güvenliği kontrollerini mutlaka yapın.

    Bir sonraki adım olarak, "Asenkron Olay Yönetimi" konusunu araştırmanızı ve Task tabanlı olay tetikleme mekanizmalarını incelemenizi öneririm. Bu, modern C# uygulamalarında performansı artırmak için kritik bir beceridir.

Bu yazıya tepkinizi paylaşın:
Zeynep Kaya

Ev ekonomisi ve kişisel organizasyon üzerine birçok yayın yönettim. Okuyucuların günlük yaşam kalitesini artıracak uygulanabilir çözümler üretmeyi hedefliyorum.

Yorumlar (0)

Yorum Yaz