Hiç bir zaman sıfır bug'lı yazılımlar yapamayacağımıza göre, en azından elimizden gelen en doğru şekilde "exception handling" yapmamız gerekiyor.
Bu mekanizmanın doğru kullanılması, yazılımda bir sorun çıktığında sorunun kaynağına rahatça ulaşabilme ve sorunu bulmak için harcanan zamanı azaltma faydalarını bize sağlıyor.
Exception handling temel ölçüde try - catch bloğunu kullanarak yaptığımız kolay bir işlem. Burada üzerinde durmak istediğimiz nokta oluşan exception'ı nasıl fırlatırsak doğru bilgi elde ederiz? Fırlattığımız exception stack trace bilgileri ne kadar işimize yarayacak ve bize nokta atışı sağlayabilecek mi?
Stack trace, başlangıçtan itibaren gerçek exception noktasına kadar metot çağrılarılarının hiyerarşisi hakkında bilgiler içerir. Ancak bazen exception'lar yanlış şekilde handle edilirse uygulama bu gerçek stack izini kaybeder.
Öncelikle "throw", "throw ex" rethrow şekillerinden bahsedelim.
Bir exception'ı rethrow etmenin doğru yöntemi "throw ex" değildir. Çünkü bize istediğimiz esas bilgiyi vermez. Sebebi; aktarılan exception nesnesi, istisnanın gerçekten oluştuğu noktadan ziyade exception'ı fırlattığımız satırın referansını tutmaktadır.
Çok basit bir örnekle inceleyelim;
Exception'ı fırlattığım satırı ekran görüntüsünde işaretledim. Bir de output'a bir bakalım bize ne söylüyor?
Malesef bu bilgi yüzlerce satır kod içeren gerçek dünyada bize yardımcı olamaz.
Dolayısıyla daha doğru bir yöntem olan throw; yöntemini kullanırız.
Bu kullanım sonrası output'a tekrar bakalım;
İşte şimdi exception'un gerçekten nerede oluştuğunu anlayabiliyoruz. Refactoring işlemlerimizde eğer projede throw ex kullanılmış yerler varsa hemen düzeltilecekler listesine ekleyebiliriz.
Şimdi, daha kullanışlı ve asıl konumuz olan ExceptionDispatchInfo sınıfından bahsedelim. .NET Framework 4.5 ile birlikte kullanıma sunulmuş bu nesne, exception'ın içerdiği stack trace bilgilerini exception'ların yakalandıkları noktada depolar.
Depolanan exception'lar, ExceptionDispatchInfo.Throw metodu çağırılarak istenilen bir zamanda ve hatta başka bir thread'de atılabilir.
Bu yöntemde exception, yakalandığı noktadan Throw() metodunun çağırıldığı noktaya kadar akmış gibi atılır.
Yakalamak istediğimiz exception'ı Capture() metodu ile bir container 'a atıp herhangi bir T anında rethrow yapıyoruz aslında.
ExceptionDispatchInfo sınıfı bir exception yakaladığımızda orjinal stack trace durumunu koruyarak o exception'ı rethrow etmemize izin verir. Hatta ve hatta sadece exception'ın nerden kaynaklandığını ve nerede yeniden ortaya çıktığını göstermekle kalmaz, aynı zamanda exception'a yol açan tüm olay zincirini de gösterir ve sorunun hangi satırda - niçin oluştuğunu çok daha kolay hale getirir.
Temel bir kullanım örneği paylaşmak gerekirse;
Burada peş peşe exception olması için basit bir kurgu yaptım ve oluşmasını beklediğim exceptionları bir koleksiyonda toplayıp en son rethrow ettim.
Output'u inceleyelim;
Evet, gördüğümüz gibi olayları zincirleme bir şekilde takip edebiliyoruz ve orjinal stack'i de kaybetmememiz tüm yaşam döngüsüne hakim olmamızı sağlıyor.
Bu örnekler tabi ki çok çok basit, daha çok karmaşık kodlarda bu konu çok çok önemli ki ExceptionDispatchInfo sınıfının bize sağladığı bu mekanizma işimize daha çok Multi Threaded uygulamalarda yarayacaktır.
Multi threaded uygulamalarda exception handling yapmak bu kadar kolay değil.
Mesela bir thread'de oluşan bir exception'ı rethrow ettik diyelim, bu exception diğer threadlerimizin işlerini durdurabilir. Bu tarz senaryolarda bu sınıfı kullanmak çok mantıklı olacaktır. Yani exception'ı child thread'de Capture() metodu ile depola, main thread'de Throw() et.
References
Comments