Uygulamalarımızı geliştirirken bir syntax hatası (Kod satırlarının sonuna noktalı virgül koymayı unutmak gibi) yaptığımızda, Visual Studio gerekli uyarıyı vererek projeyi derlememizi engelleyecektir. Ancak çalışma anında ortaya çıkabilecek hataları Visual Studio’nun önceden tespit edebilmesi mümkün değildir. Bu yüzden çalışma anında ortaya çıkabilecek hataların uygulamamızı çökertmesine izin vermemek için Try-Catch-Finally ile istisnai durum yönetimine başvururuz.
class Program { static void Main(string[] args) { Console.Write("Birinci sayıyı giriniz: "); int sayi_1 = Convert.ToInt32(Console.ReadLine()); Console.Write("İkinci sayıyı giriniz: "); int sayi_2 = Convert.ToInt32(Console.ReadLine()); double sonuc = sayi_1 / sayi_2; Console.WriteLine("Birinci sayının ikinci sayıya bölümü:{0}", sonuc); } }
Yukarıdaki uygulama Visual Studio tarafından sorunsuz bir şekilde derlenecektir ve doğru değerler girildiği sürece program sorunsuz bir şekilde çalışacaktır. Ancak programı kullanan kullanıcı klavyeden sayı yerine harf veya karakter girdiğinde veya sayi_2 değişkenine sıfır değerini atadığında (bir sayının sıfıra bölümü sonsuzdur) uygulamamız çökecektir.
Çalışma anında ortaya çıkan hataların uygulamamızı çökertmemesi için Try-Catch-Finally bloklarını kullanırız.
Try-Catch-Finally Blokları
Try Bloğu: Çalışma anında hata çıkarma olasılığı olan kodlarımızı Try bloğu içerisine yazarız. Eğer Try bloğu içerisine yazılmış olan kodlarda bir hata meydana gelirse, oluşan hata bir Exception nesnesi olarak catch bloğuna gönderilir.
Catch Bloğu: Try bloğu içerisine yazılmış olan kodlarda bir hata meydana geldiği an, program Try bloğundan çıkarak Catch bloğuna girer. Uygulamamız çalışırken hata oluşması durumunda, uygulanmasını istediğimiz çözüm senaryosunu Catch bloğu içerisine yazarız.
Finally Bloğu: Try bloğu içerisinde bir hata meydana gelmediği sürece Catch bloğu içerisindeki kodlar çalışmaz. Ancak Finally Bloğu hata meydana gelse de, gelmese de her halükarda çalışır. Finally opsiyonel bir bloktur, istenilmediği taktirde yazılmayabilir.
class Program { static void Main(string[] args) { try { Console.Write("Birinci sayıyı giriniz: "); int sayi_1 = Convert.ToInt32(Console.ReadLine()); Console.Write("İkinci sayıyı giriniz: "); int sayi_2 = Convert.ToInt32(Console.ReadLine()); double sonuc = sayi_1 / sayi_2; Console.WriteLine("Birinci sayının ikinci sayıya bölümü:{0}", sonuc); } catch(Exception e) { Console.WriteLine(e.Message); } finally { // finally bloğu opsiyoneldir, yazılmayabilir. } } }
Artık sayı yerine harf girildiğinde veya sayi_2 değişkenine sıfır değeri atandığında uygulamamız çökmeyecektir. Hata meydana geldiği an arkaplanda bir Exception nesnesi oluşturulup Catch bloguna parametre olarak gönderilecektir. Bu parametre aracılığıyla oluşan hata hakkında bilgi alınabilir.
Yukarıdaki örnekte Exception’da ki hata mesajı kullanıcıya gösterilmek üzere ekrana yazdırıldı ancak profesyonelce geliştirilen projelerde Exception’da ki hata mesajı doğrudan kullanıcıya sunulmaz. Bunun başlıca iki sebebi bulunmaktadır.
- Exception’da ki hata mesajı genellikle kullanıcıların anlayamayacağı teknik terimleri içerir.
- Exception’da ki hata mesajı uygulamamız hakkında bilinmemesi gereken bilgileri içeriyor olabilir.
Bu yüzden Exception’da ki hata mesajını genellikle loglamak amacıyla kullanırız.
Oluşan Hataları Filtreleme
Try bloğu içerisine yazdığımız kodlarda farklı türden hatalar meydana gelebilir. Eğer her hata türü için farklı bir çözüm senaryomuz varsa, oluşan hataları filtrelememiz gerekir. Yukarıdaki örneğimizde iki farklı hata söz konusuydu; ilki klavyeden sayı yerine harf veya karakter girildiğinde ortaya çıkarken, ikincisi sayi_2 değişkenine sıfır değeri atandığında ortaya çıkmaktaydı. Oluşan hataları filtreleyecek şekilde uygulamamızı yeniden yazacak olursak;
class Program { static void Main(string[] args) { try { Console.Write("Birinci sayıyı giriniz: "); int sayi_1 = Convert.ToInt32(Console.ReadLine()); Console.Write("İkinci sayıyı giriniz: "); int sayi_2 = Convert.ToInt32(Console.ReadLine()); double sonuc = sayi_1 / sayi_2; Console.WriteLine("Birinci sayının ikinci sayıya bölümü:{0}", sonuc); } catch (FormatException exception) { // Klavyeden sayı yerine harf veya karakter girildiğinde bu catch bloğu çalışacak. Console.WriteLine("Hata! Sadece sayı girilebilir. Hata Mesajı:{0}", exception.Message); } catch (DivideByZeroException exception) { // sayi_2 değişkenine sıfır değeri atandığında bu catch bloğu çalışacak. Console.WriteLine("Hata! Bir sayının sıfıra bölümü sonsuzdur. Hata Mesajı:{0}", exception.Message); } catch (Exception exception) { // Öngördüğümüz hatalar haricinde bir hata oluştuğunda bu catch bloğu çalışacak. Console.WriteLine("Beklenmedik bir hata oluştu. Hata Mesajı:{0}", exception.Message); } } }
“FormatException” ve “DivideByZeroException” gibi bir çok hazır Exception sınıfı bulunmakta. Try bloğunda hata meydana geldiği an arkaplanda bir Exception nesnesi oluşturulur ve Catch blokları yukarıdan aşağıya incelenir, oluşan hata türü hangi Catch bloğuna uyuyorsa o Catch bloğu çalışır. Klavyeden sayı yerine harf veya karakter girildiğinde ilk Catch bloğu çalışacaktır, sayi_2 değişkenine sıfır değeri atandığında da ikinci Catch bloğu çalışacaktır. “FormatException” ve “DivideByZeroException” haricinde bir hata meydana geldiğinde de üçüncü Catch bloğu çalışacaktır.
“catch(Exception exception)” şeklinde tanımlanan Catch bloğu tüm hata türlerini kapsar. O yüzden hata türüne göre filtreleme işlemi yaparken “catch(Exception exception)” bloğunu en sona yazmalıyız.
try { Console.Write("Birinci sayıyı giriniz: "); int sayi_1 = Convert.ToInt32(Console.ReadLine()); Console.Write("İkinci sayıyı giriniz: "); int sayi_2 = Convert.ToInt32(Console.ReadLine()); double sonuc = sayi_1 / sayi_2; Console.WriteLine("Birinci sayının ikinci sayıya bölümü:{0}", sonuc); } catch (Exception exception) { Console.WriteLine("Beklenmedik bir hata oluştu. Hata Mesajı:{0}", exception.Message); } catch (FormatException exception) { Console.WriteLine("Hata! Sadece sayı girilebilir. Hata Mesajı:{0}", exception.Message); } catch (DivideByZeroException exception) { Console.WriteLine("Hata! Bir sayının sıfıra bölümü sonsuzdur. Hata Mesajı:{0}", exception.Message); }
Eğer “catch (Exception exception)” bloğunu en üste yazarsak; Catch blokları yukarıdan aşağıya doğru incelendiği için ve “catch (Exception exception)” bloğu da tüm hata türlerini kapsadığı için; “catch (FormatException exception)” ve “catch (DivideByZeroException exception)” blokları hiç bir zaman çalışmayacaktır. Tüm hata türleri “catch (Exception exception)” bloğu tarafından yakalanacaktır.
Serdar YILMAZ
Hocam ellerinize sağlık. Çok faydalı bir yazı olmuş. Teşekkürlerimi sunuyorum.