C# ObjectDisposedException hatası, IDisposable kullanan bir nesne Dispose edildikten sonra onun metotlarına veya özelliklerine yeniden erişilmeye çalışıldığında alınır. Nesnenin referansı hâlâ bir değişkende, alanda ya da parametrede bulunabilir; ancak bu durum nesnenin kullanılabilir kaynaklarının hâlâ açık olduğu anlamına gelmez.
Dispose sonrasında oluşan davranış her tür için aynı değildir. Bazı üyeler çağrıldığında ObjectDisposedException oluşabilirken, bazı üyeler türün sözleşmesine göre farklı davranabilir. Sorunu bulmak için nesnenin nerede oluşturulduğu, nerede Dispose edildiği ve hangi noktada yeniden kullanılmaya çalışıldığı izlenmelidir.
ObjectDisposedException hatası neden alınır?
Bir nesne oluşturulduğunda yalnızca bellekte bir referans elde edilmez; nesne bazen işletim sistemi kaynağı, akış, dosya, bağlantı veya başka bir yönetilmesi gereken kaynakla ilişkilendirilir. Dispose çağrısı, bu kaynağın artık kullanılmayacağını nesneye bildirir ve türün tasarımına göre gerekli temizleme işlemlerini başlatır. Temizleme tamamlandıktan sonra aynı nesneyi kullanmaya devam etmek geçersiz bir yaşam döngüsü oluşturabilir.
Bu hatanın yaygın nedenlerinden biri, nesnenin yaşam süresini yöneten kod ile nesneyi kullanan kodun birbirinden ayrılmasıdır. Örneğin bir metot oluşturduğu akışı kapattıktan sonra aynı akışı çağıran metoda döndürebilir. Dışarıdaki kod geçerli bir referans almış olsa bile, referansın gösterdiği nesne artık kullanılabilir durumda olmayabilir.
Bir başka neden, using kapsamından çıkan bir nesnenin kapsam dışındaki başka bir değişken veya alan üzerinden kullanılmaya devam etmesidir. Burada sorun referansın silinmesi değildir. Sorun, referansın hâlâ aynı nesneyi göstermesine rağmen o nesnenin kaynak yaşam süresinin sona ermiş olmasıdır.
C# bilginin hangi konularda güçlendirilmesi gerektiğini görmek için C# bilgi testini kullanabilirsin. Bu araç bir C# programı değil, mevcut bilgi düzeyini ölçmeye yardımcı olan bir değerlendirmedir.
IDisposable, Dispose ve using bloğu nasıl çalışır?

IDisposable, kaynak kullanan nesnelerin yaşam döngüsünü açıkça yönetmek için kullanılan bir sözleşmedir. Bu arayüzü uygulayan türler, genellikle kaynak bırakma işlemlerini Dispose metodu üzerinden sunar. Dispose çağrıldığında nesnenin belleği hemen yok olmak zorunda değildir; belleğin geri alınması çöp toplayıcının görevidir. Ancak dosya, akış veya bağlantı gibi kaynakların kullanımını sonlandırma sorumluluğu Dispose işlemine aittir.
using bloğu, nesnenin yalnızca belirli bir kapsam içinde kullanılacağını ifade eder. Kapsam sona erdiğinde, normal akış gerçekleşse de blok içinde başka bir hata oluşsa da Dispose çağrısının yapılmasını otomatikleştirir. Bu nedenle using, temizleme kodunun unutulması ihtimalini azaltır ve nesnenin yaşam süresini daha görünür hâle getirir.
“Dispose edilen nesneyi yeniden kullanmak yerine, nesnenin sahibi ve yaşam süresi belirlenmelidir.”
Buradaki sahiplik, nesneyi kimin oluşturduğundan çok, kullanım süresini ve Dispose sorumluluğunu kimin yönettiğiyle ilgilidir. Nesneyi oluşturan kapsam onu yalnızca kendi işlemi boyunca kullanacaksa Dispose işlemi de aynı kapsamda yapılmalıdır. Başka bir metoda gönderilecek nesnenin yaşam süresi ise çağıran ve çağrılan kod arasında açıkça belirlenmelidir.
Kaynak yaşam döngüsü, yalnızca tek bir dile ait ayrıntı değildir. Yazılım öğrenme sürecini farklı hedeflerle birlikte planlamak için genel yazılım eğitimi sayfasındaki program başlıklarını inceleyebilirsin.
using kapsamı dışında erişim: çalışan MemoryStream örneği

using bloğu, bloğun sonunda içindeki nesne için Dispose çağrılmasını sağlar. Değişkenin referansı blok dışına taşınsa bile nesnenin kaynak kullanım süresi sona erer. Aşağıdaki örnekte aynı MemoryStream değişkeni üzerinden Length özelliğine erişilmeye çalışılır:
using System;
using System.IO;
class Program
{
static void Main()
{
MemoryStream stream = new MemoryStream();
using (stream)
{
stream.WriteByte(42);
}
try
{
Console.WriteLine(stream.Length);
}
catch (ObjectDisposedException ex)
{
Console.WriteLine(ex.GetType().Name);
}
}
}
Beklenen çıktı tek satırdır:
ObjectDisposedException
using bloğu kapandığında stream.Dispose() çağrılır. stream değişkeni hâlâ aynı nesnenin referansını tutar, ancak MemoryStream için kullanım yaşam süresi tamamlanmıştır. Bu nedenle hata yalnızca yeni veri yazma gibi işlemlerde değil, bu örnekte olduğu gibi stream.Length özelliğini okumaya çalışırken de ortaya çıkabilir.
ObjectDisposedException kaynağını üç teşhis yoluyla bul
Hatanın kaynağını bulmak için yalnızca istisnanın oluştuğu satıra bakmak yeterli olmayabilir. Nesnenin nerede oluşturulduğunu, kimin sahibi olduğunu ve hangi noktada elden çıkarıldığını birlikte incelemek gerekir.
using bloğunun dışına taşan nesne
using içinde oluşturulan veya kullanılan bir nesne alan değerine atanabilir, dönüş değeri olarak gönderilebilir, bir callback içine aktarılabilir ya da başka bir metoda parametre olarak verilebilir. Referansın dışarı taşınması, nesnenin yaşam süresini uzatmaz. Dışarıdaki kod, using sona erdikten sonra bu nesneyi kullanıyorsa hata oluşabilir.
erken Dispose çağrısı
Bazen nesneyi kullanan kod tamamlanmadan başka bir metot, bileşen veya sahip nesne Dispose çağırır. Özellikle aynı akışın birden fazla metot arasında paylaşıldığı durumlarda, elden çıkarma işleminin hangi kod tarafından ve hangi sırada yapıldığını kontrol et. Kullanım devam ederken yapılan erken Dispose çağrısı, sonraki erişimi geçersiz hâle getirebilir.
yaşam süresi yanlış tasarlanmış alan
Bir sınıf alanının tuttuğu kaynak, alanı kullanan nesneden daha kısa ömürlü olabilir. Örneğin uzun süre yaşayan bir nesne, yalnızca geçici bir using bloğu için oluşturulmuş akış nesnesini alanında saklarsa ilerleyen bir metot geçersiz bir referansı kullanabilir. Burada alanın sahibi ile kaynağın gerçek sahibi ve kullanım süresi birbirine uymuyor olabilir.
Teşhis için şu kontrol sırasını izle:
- Nesnenin oluşturulduğu yeri bul.
- Nesnenin sahibi olan kodu belirle.
- Tüm
Disposeveusingnoktalarını izle. - Alan, parametre ve dönüş değeri akışını kontrol et.
- İstisna yığın izinde ilk geçersiz erişim noktasını incele.
“Dispose edilen nesneyi yeniden kullanmak yerine, nesnenin sahibi ve yaşam süresi belirlenmelidir.”
Bu adımlardaki C# kavramlarını ne ölçüde bildiğini görmek için ücretsiz C# bilgi testini yalnızca seviye ölçümü amacıyla kullanabilirsin.
ObjectDisposedException nasıl düzeltilir?
ObjectDisposedException hatasını düzeltmek için Dispose edilmiş nesneye erişimi engellemen gerekir. Bunun yolu, kullanımı nesnenin geçerli olduğu kapsama taşımak veya sahiplik ile yaşam süresini yeniden tasarlamaktır.
Kullanımı nesnenin geçerli olduğu kapsama taşı
Kaynak yalnızca bir metotta gerekiyorsa onu using içinde oluştur, kullan ve kapat. Metodun dışına nesnenin kendisini değil, üretilen metni, byte[] verisini veya sonucu döndür. Böylece çağıran kod, artık geçerli olmayan kaynağa değil, kaynaktan elde edilen veriye erişir.
Sahipliği ve yaşam süresini yeniden tasarla
Nesneyi kim oluşturuyorsa sahipliği ve kullanım süresini kim yönetiyorsa bu sorumluluklar açık olmalıdır. Yalnızca iç kullanım için oluşturulan kaynakları ilgili metotta kapat. Çağıran kodun sahip olduğu bir kaynağı, kullanım bitmeden Dispose etme. Uzun ömürlü alanların Dispose zamanını da onları kullanan bileşenin yaşamıyla hizala.
- Kaynağı hangi kod oluşturuyor?
- Dispose çağrısı hangi kodun sorumluluğunda?
- Nesne, kapatıldıktan sonra başka bir metot, alan, görev veya geri çağırım tarafından kullanılıyor mu?
| Teşhis | Sahiplik veya yaşam süresi işareti | Öncelikli çözüm |
|---|---|---|
| Kapsam | using bittikten sonra aynı kaynak kullanılıyor |
Kullanımı kapsama taşı, sonucu döndür |
| Sahiplik | Bir metot, çağıranın verdiği kaynağı kapatıyor | Sahipliği netleştir, çağıranın kaynağını kapatma |
| Yaşam süresi | Alan, görev veya geri çağırım kapanmış nesneyi paylaşıyor | Ömrü bileşenle hizala, gerekirse yeniden oluştur |
Kaynak kısa ömürlü ve durumu yeniden kurulabilir olduğunda yeni bir örnek oluşturmak düşünülebilir. Ancak oturum, işlem veya korunması gereken bir durum söz konusuysa yalnızca nesneyi yeniden oluşturmak yeterli olmayabilir. Bu durumda sahibi ve yaşam süresi yeniden tasarlanmalıdır.
“Dispose edilen nesneyi yeniden kullanmak yerine, nesnenin sahibi ve yaşam süresi belirlenmelidir.”
Yazılım öğrenme seçenekleri hakkında genel bilgi edinmek için genel yazılım eğitimi sayfasını inceleyebilirsin.
Sık Sorulan Sorular
Dispose çağrısından sonra nesne yeniden oluşturulmalı mı?
Her zaman değil. Kaynak kısa ömürlü ve durumu kolayca yeniden kurulabilir ise yeni örnek oluşturulabilir. Oturum veya işlem durumu korunacaksa sahiplik ve yaşam süresi yeniden ele alınmalıdır.
using bloğu bittikten sonra değişken neden hâlâ nesneye erişebiliyor?
using bloğu sona erdiğinde Dispose çağrılır, fakat değişkenin referansı otomatik olarak null yapılmaz. Değişken nesneyi göstermeye devam eder, ancak sonraki kullanım nesnenin türüne bağlı olarak ObjectDisposedException oluşturabilir.
ObjectDisposedException ile NullReferenceException arasındaki fark nedir?
ObjectDisposedException, var olan fakat yaşam süresi sona ermiş bir nesnenin kullanılmaya çalışıldığını gösterir. NullReferenceException ise değişkenin herhangi bir nesneyi göstermediği durumda üyeye erişildiğini belirtir.
Bir metot aldığı IDisposable nesneyi kendisi Dispose etmeli mi?
Genellikle hayır. Nesneyi çağıran kod oluşturup sahipleniyorsa metot onu kullanım bitmeden kapatmamalıdır. Nesne metot içinde oluşturulmuş ve yalnızca o metotta kullanılıyorsa Dispose sorumluluğu o metoda ait olabilir.
Bu hatayı çözmenin anahtarı, nesnenin yalnızca nasıl kapatıldığını değil, kimin tarafından oluşturulup ne zamana kadar kullanılacağını da netleştirmektir.