Yükleniyor...

C# IDisposable ve Using Pattern

C#’ta IDisposable ve using pattern kullanımını öğrenin. Kaynak yönetimi, bellek temizliği ve güvenli nesne yaşam döngüsü anlatılıyor.

C# dilinde IDisposable arayüzü, bellek dışında (örneğin dosya, ağ, veritabanı, GDI nesneleri gibi) kullanılan kaynakları doğru şekilde serbest bırakmak için tasarlanmıştır. Bu kaynakların sistem tarafından otomatik temizlenmesini beklemek yerine, Dispose metodu ve using yapısı ile deterministik (öngörülebilir) temizlik yapılır.


IDisposable Nedir?

IDisposable arayüzü, yalnızca bir tane metot içerir:


public interface IDisposable
{
    void Dispose();
}

Bir sınıf IDisposable’ı uyguladığında, sahip olduğu yönettiği (managed) veya yönetilmeyen (unmanaged) kaynakları Dispose() metodunda serbest bırakmalıdır. .NET’in çöp toplayıcısı (GC) yönetilmeyen kaynakları otomatik temizleyemez; bu yüzden Dispose() çağrısı önemlidir.


Basit Bir IDisposable Örneği

Aşağıdaki örnekte DosyaYazici sınıfı bir dosya akışı açar ve IDisposable arayüzünü uygular. Dispose() çağrıldığında dosya otomatik olarak kapatılır.


using System;
using System.IO;

class DosyaYazici : IDisposable
{
    private readonly StreamWriter _writer;
    private bool _disposed = false;

    public DosyaYazici(string dosyaYolu)
    {
        _writer = new StreamWriter(dosyaYolu);
    }

    public void Yaz(string metin)
    {
        if (_disposed)
            throw new ObjectDisposedException(nameof(DosyaYazici));

        _writer.WriteLine(metin);
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            _writer.Close();
            _writer.Dispose();
            _disposed = true;
            Console.WriteLine("Dosya kapatıldı ve kaynaklar serbest bırakıldı.");
        }
    }
}

class Program
{
    static void Main()
    {
        var yazici = new DosyaYazici("test.txt");
        yazici.Yaz("Merhaba Dünya!");
        yazici.Dispose(); // kaynak serbest bırakıldı
    }
}

using Bloğu ile Kaynak Yönetimi

using anahtar kelimesi, IDisposable nesneleri otomatik olarak temizlemek için kullanılır. using bloğu bittiğinde nesnenin Dispose() metodu otomatik çağrılır.


using (var dosya = new StreamWriter("log.txt"))
{
    dosya.WriteLine("Uygulama başladı: " + DateTime.Now);
} // Dispose() burada otomatik çağrılır

Bu sayede hata olsa bile kaynak sızıntısı yaşanmaz. using bloğu, try/finally yapısına eşdeğerdir:


var dosya = new StreamWriter("log.txt");
try
{
    dosya.WriteLine("Uygulama başladı.");
}
finally
{
    dosya.Dispose();
}

Birden Fazla using Aynı Satırda

C# 8.0’dan itibaren “using declaration” özelliğiyle daha sade bir sözdizimi kullanabilirsiniz. Bu şekilde süslü parantez gerekmeden, scope bitiminde otomatik Dispose() çağrılır.


using var dosya = new StreamWriter("output.txt");
dosya.WriteLine("Bu dosya program bittiğinde otomatik kapanır.");

Dispose Pattern (Gelişmiş Kullanım)

Eğer sınıfın yönetilmeyen kaynakları varsa veya başka IDisposable nesnelere sahip alt sınıfları olacaksa, Dispose Pattern uygulanmalıdır. Bu desen, Dispose(bool disposing) yöntemiyle yönetilen ve yönetilmeyen kaynakları ayırarak serbest bırakmayı sağlar.


using System;

class KaynakYoneticisi : IDisposable
{
    private IntPtr _unmanagedResource; // örnek: dosya tanıtıcısı, socket, GDI nesnesi
    private bool _disposed = false;

    public KaynakYoneticisi()
    {
        _unmanagedResource = IntPtr.Zero; // örnek oluşturma
    }

    // Temel Dispose metodu
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this); // Finalize çağrılmasını önle
    }

    // Korunan sanal metot, alt sınıflar genişletebilir
    protected virtual void Dispose(bool disposing)
    {
        if (_disposed) return;

        if (disposing)
        {
            // yönetilen kaynakları serbest bırak
        }

        // yönetilmeyen kaynakları serbest bırak
        if (_unmanagedResource != IntPtr.Zero)
        {
            // örnek: CloseHandle(_unmanagedResource);
            _unmanagedResource = IntPtr.Zero;
        }

        _disposed = true;
    }

    // Finalizer (yönetilmeyen kaynaklar için güvence)
    ~KaynakYoneticisi()
    {
        Dispose(false);
    }
}

Bu yapı, GC.SuppressFinalize() sayesinde gereksiz finalizer çağrılarını engeller ve yönetilmeyen kaynakların güvenli şekilde serbest bırakılmasını garanti eder.


Asenkron Kaynak Yönetimi: IAsyncDisposable

C# 8.0 ile gelen IAsyncDisposable arayüzü, asenkron kaynak temizliği için kullanılır. Örneğin bir ağ bağlantısı veya akış asenkron şekilde kapatılabilir.


using System;
using System.IO;
using System.Threading.Tasks;

class LogYazici : IAsyncDisposable
{
    private readonly StreamWriter _writer = new StreamWriter("async_log.txt");

    public async ValueTask DisposeAsync()
    {
        await _writer.FlushAsync();
        _writer.Dispose();
        Console.WriteLine("Asenkron log yazıcı kapatıldı.");
    }

    public async Task YazAsync(string mesaj)
    {
        await _writer.WriteLineAsync(mesaj);
    }
}

class Program
{
    static async Task Main()
    {
        await using var log = new LogYazici();
        await log.YazAsync("Program başladı.");
    }
}

Yaygın Hatalar ve Dikkat Edilecek Noktalar


Örnek: Dosya İşlemi Yapan Servis

Aşağıdaki örnekte bir servis sınıfı, FileStream ve StreamReader gibi kaynakları yönetir. using sayesinde dosyalar işlem bitince otomatik kapatılır.


using System;
using System.IO;

class DosyaServisi
{
    public string Oku(string dosyaYolu)
    {
        using var sr = new StreamReader(dosyaYolu);
        return sr.ReadToEnd();
    }

    public void Yaz(string dosyaYolu, string veri)
    {
        using var sw = new StreamWriter(dosyaYolu, append: true);
        sw.WriteLine(veri);
    }
}

class Program
{
    static void Main()
    {
        var servis = new DosyaServisi();
        servis.Yaz("rapor.txt", "Yeni kayıt eklendi.");
        Console.WriteLine(servis.Oku("rapor.txt"));
    }
}

TL;DR

  • IDisposable, kaynakları manuel olarak serbest bırakmayı sağlar (Dispose()).
  • using yapısı, Dispose()’u otomatik çağırarak kaynak sızıntısını önler.
  • Dispose Pattern, hem yönetilen hem yönetilmeyen kaynakları güvenli biçimde temizler.
  • IAsyncDisposable, asenkron işlemlerde (ör. dosya, ağ) kaynakları asenkron kapatır.
  • GC.SuppressFinalize(), finalize çağrılarını engelleyerek performansı artırır.

İlişkili Makaleler

C# File IO ve Stream API

C#’ta File IO ve Stream API kullanımını öğrenin. Dosya okuma, yazma ve veri akışı işlemleri örneklerle anlatılıyor.