Dene / Nihayet (Catch olmadan) istisnayı balonlar mı?


116

Cevabın EVET olduğuna neredeyse pozitifim. Bir Sonunda Dene bloğu kullanırsam, ancak bir Catch bloğu kullanmazsam, herhangi bir istisna OLACAKTIR. Doğru?

Genel olarak uygulama hakkında herhangi bir fikriniz var mı?

Seth

Yanıtlar:


131

Evet, kesinlikle olacak. Bloğunuzun finallybir istisna atmadığını varsayarsak , elbette, bu durumda, başlangıçta atılan bloğu etkin bir şekilde "değiştirecektir".


13
@David: C # 'ta nihayet bloktan dönemezsiniz.
Jon Skeet

3
msdn belgeleri de bu yanıtı doğrular: Alternatif olarak, çağrı yığınının yukarısındaki bir dene-son ifadesinin dene bloğunda atılan istisnayı yakalayabilirsiniz. Diğer bir deyişle, dene-nihayet ifadesini içeren yöntemi çağıran yöntemde veya bu yöntemi çağıran yöntemde veya çağrı yığınındaki herhangi bir yöntemde istisnayı yakalayabilirsiniz. İstisna yakalanmazsa, final bloğunun yürütülmesi, işletim sisteminin bir istisna çözme işlemini tetiklemeyi seçip seçmemesine bağlıdır.
geniş bant

60

Genel olarak uygulama hakkında herhangi bir fikriniz var mı?

Evet. Dikkatli ol . Nihai bloğunuz çalışırken, işlenmemiş, beklenmedik bir istisna atıldığı için çalışması tamamen mümkündür . Bu, bir şeyin kırıldığı ve tamamen beklenmedik bir şeyin olabileceği anlamına gelir .

Bu durumda, muhtemelen son bloklarda kodu çalıştırmamanız gerekir. Nihayet bloğundaki kod, bağlı olduğu alt sistemlerin sağlıklı olduğunu varsaymak için oluşturulabilir, ancak aslında derinlemesine kırılabilirler. Nihayet bloğundaki kod işleri daha da kötüleştirebilir.

Örneğin, sık sık bu tür şeyler görüyorum:

DisableAccessToTheResource();
try
{
    DoSomethingToTheResource();
}
finally
{
    EnableAccessToTheResource();
}

Bu kodun yazarı, "Dünyanın durumuna geçici bir mutasyon yapıyorum; devleti bana çağrılmadan önceki haline getirmem gerekiyor" diye düşünüyor. Ama bunun ters gidebileceği tüm yolları düşünelim.

İlk olarak, kaynağa erişim arayan tarafından zaten devre dışı bırakılmış olabilir; bu durumda, bu kod, muhtemelen vaktinden önce yeniden etkinleştirir.

İkincisi, DoSomethingToTheResource bir istisna atarsa, kaynağa erişimi etkinleştirmek için yapılacak doğru şey budur ??? Kaynağı yöneten kod beklenmedik şekilde bozuldu . Bu kod, aslında "yönetim kodu bozulursa, diğer kodun da bu bozuk kodu en kısa sürede çağırabildiğinden emin olun, böylece korkunç bir şekilde başarısız olabilir " diyor. Bu kötü bir fikir gibi görünüyor.

Üçüncü olarak, DoSomethingToTheResource bir istisna atarsa, EnableAccessToTheResource'un da bir istisna oluşturmayacağını nasıl bileceğiz? Kaynağın kullanımı ne kadar kötü olursa olsun temizleme kodunu da etkileyebilir, bu durumda orijinal istisna kaybolacak ve sorunun teşhis edilmesi daha zor olacaktır.

Sonunda dene bloklarını kullanmadan böyle kod yazma eğilimindeyim:

bool wasDisabled = IsAccessDisabled();
if (!wasDisabled)
    DisableAccessToTheResource();
DoSomethingToTheResource();
if (!wasDisabled)
    EnableAccessToTheResource();

Artık devlet, olması gerekmedikçe mutasyona uğramaz. Arayanın durumu artık karışık değil. Ve şimdi, DoSomethingToTheResource başarısız olursa, erişimi yeniden etkinleştirmeyiz. Bir şeyin derinlemesine bozuk olduğunu varsayıyoruz ve kodu çalıştırmaya devam ederek durumu daha da kötüleştirme riskini almayız. Mümkünse, arayanın sorunla ilgilenmesine izin verin.

Öyleyse nihayet bloğu çalıştırmak ne zaman iyi bir fikirdir? İlk olarak, istisna beklendiğinde. Örneğin, başka biri kilitlediği için bir dosyayı kilitleme girişiminin başarısız olmasını bekleyebilirsiniz. Bu durumda istisnayı yakalamak ve kullanıcıya bildirmek mantıklıdır. Bu durumda neyin kırıldığına dair belirsizlik azalır; temizlik yaparak işleri daha da kötüleştirmeniz olası değildir.

İkincisi, temizlediğiniz kaynak kıt bir sistem kaynağı olduğunda. Örneğin, bir nihayet bloğundaki bir dosya tutamacını kapatmak mantıklıdır. ("Kullanmak" elbette bir dene-son bloğu yazmanın başka bir yoludur.) Dosyanın içeriği bozulmuş olabilir, ancak şimdi bununla ilgili yapabileceğiniz hiçbir şey yok. Dosya tanıtıcısı er ya da geç kapatılacak, bu yüzden daha sonra değil de daha erken olabilir.


7
Yine de, hata işleme söz konusu olduğunda, bir endüstri olarak nasıl bir araya gelemediğimize dair daha fazla örnek. İstisnalardan daha iyi önerebileceğim bir şey olduğundan değil, ama umarım gelecekte, makul bir şekilde kolayca yapılabilecek doğru eylem tarzına yol açma olasılığı daha yüksektir.
Jon Skeet

Vb.net'te, bir Nihayet bloğundaki kodun hangi istisnanın beklemede olduğunu bilmesi mümkündür. Biri "yapmadı; aksi takdirde tamam" seçeneğini "durum bozuldu" dan ayırt etmek için bir istisna hiyerarşisi oluşturduysa, bir Sonunda bloğu ancak bekleyen istisna kötü olanlardan biri değilse çalıştırılabilir. Bertaraf etme / temizleme rutinlerinin istisnaları yakalamasını ve bir DisposerFailedException ("kötü" kategoride olan ve InnerException olarak orijinal istisnayı içeren) atmasını seviyorum. Bunu kolaylaştırmak için Dispose (İstisna Olarak İstisna) içeren standart bir iDisposableEx arayüzü görmek istiyorum.
supercat

Bir nesne kötü durumdayken bir istisnanın meydana gelebileceği ve temizleme girişiminin işleri daha da kötüleştireceği durumlar olduğunu takdir etmeme rağmen, bu tür sorunların muhtemelen delegelerin yardımıyla temizleme kodunda ele alınması gerektiğini düşünüyorum. Örneğin bir kilit sarıcı, kilitli nesne geçersiz bir durumda olduğunda ve aksi takdirde temizlendiğinde ayarlanabilen bir "CheckIfSafeToUnlock (İstisna Olarak İstisna)" işlev temsilcisini açığa çıkarabilir. Kilidi serbest bırakmadan önce, paketleyici delegeyi kontrol edebilir; boş değilse, çalıştırabilir ve kilidi ancak true dönerse serbest bırakabilir.
supercat

Bir sarmalayıcının böyle bir temsilci kullanması, nesne durumunu değiştiren kodun, kesintiye uğrarsa uygun temizleme eylemini seçmesine izin verir. Bu tür eylemler, veri yapısının onarılmasını ve True döndürülmesini, orijinali saran başka bir "daha ciddi" istisna atılmasını veya False döndürülürken orijinal istisnanın süzülmesine izin verilmesini içerebilir.
supercat

2
Eric, harika cevabın için teşekkürler. Sanırım iki soru sormalıydım çünkü hem sen hem de Jon haklısınız. Her durumda, size olumlu oy veriliyor. Soruya gösterdiğiniz ilgi için teşekkür ederiz.
Seth Spearman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.