C Sharp Programlama Dili/İstisnai durum yakalama mekanizması

Ders 23. İstisnai durum yakalama mekanizması


Muhtemelen şu ana kadar fark etmişsinizdir. Ancak yine de söylemek istiyorum. Programlarımızdaki hatalar ikiye ayrılır:

  1. Derleme zamanı hataları
  2. Çalışma zamanı hataları

Programımızda bir derleme zamanı hatası oluşursa derleme işlemi olmaz. Genellikle derleme zamanı hataları yanlış söz diziminden (sintaks) kaynaklanır ve tespiti kolaydır. Çalışma zamanı hataları ise daha çok mantıksal yanlışlıklardan kaynaklanır ve tespiti nispeten daha zordur. Örneğin kullanıcının girdiği iki sayıyı toplayan bir program yazdığımızı düşünelim. Kullanıcı sayıların yerine herhangi bir harf girerse programımız çalışma zamanı hatası verir ve kendisini sonlandırır. Böyle bir durumu engellemek için toplama işlemini yapmadan önce kullanıcının girdiği veriyi bir kontrolden geçirebiliriz. Örneğin kullanıcının girdiği stringin içinde foreach döngüsü yardımıyla dolaşıp herhangi bir rakam olmayan karakter varsa toplama işleminin yapılmamasını sağlayabiliriz. Ancak takdir edersiniz ki bu çok zahmetli bir yöntemdir. Üstelik bu kadar basit bir program için bu kadar zahmetli bir kod yazdığımızı düşünürsek büyük ölçekli projelerde zamanımızın çoğunu hata yakalamaya ayırmamız gerekirdi. İşte istisnai durum yakalama mekanizması böyle bir durumda zamanımızı büyük oranda kısaltır. İstisnai durum yakalama mekanizması programımızın bir çalışma zamanı hatasıyla karşılaştığında hata verip kendini sonlandırması yerine daha farklı işlemler yapılabilmesini sağlar. Şimdi kod yazmaya başlayabiliriz.

Hatanın türünden bağımsız hata yakalama değiştir

 using System;
 class deneme
 {
    static void Main()
    {
       string a=Console.ReadLine();
       string b=Console.ReadLine();
       int toplam=Int32.Parse(a)+Int32.Parse(b);
       Console.WriteLine(toplam);
    }
 }

Bu programın şimdiye kadar yazdığımız programlardan farkı yok. Kullanıcının girdiği değerlerden en az biri sayı değilse program hata verip sonlanacaktır. Bunu önlemek için programı şöyle yazabiliriz:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          string a=Console.ReadLine();
          string b=Console.ReadLine();
          int toplam=Int32.Parse(a)+Int32.Parse(b);
          Console.WriteLine(toplam);
       }
       catch
       {
          Console.WriteLine("Sayı girmelisiniz!");
       }
    }
 }

Bu programda try blokunda herhangi bir çalışma zamanı hatasıyla karşılaşılır ise catch blokundaki satırlar çalıştırılır ve akış catch blokunun dışından devam eder. Eğer try blokunda herhangi bir çalışma zamanı hatasıyla karşılaşılmazsa catch blokundaki satırlar çalıştırılmaz ve programın akışı catch blokunun dışından devam eder. try ve catch blokları aynı blok içinde olmalıdır. Ayrıca try'dan hemen sonra catch gelmelidir. Başka bir örnek:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          string a=Console.ReadLine();
          string b=Console.ReadLine();
          int toplam=Int32.Parse(a)+Int32.Parse(b);
          Console.WriteLine(toplam);
       }
       catch
       {
          Console.WriteLine("Sayı girmelisiniz!");
       }
       finally
       {
          Console.WriteLine("Program sonlandı!");
       }
    }
 }

Burada finally blokunda hata oluşsa da oluşmasa da çalıştırılması istenen satırlar yazılır. finally blokunu belirtmek zorunda değiliz. Ancak try ve catch blokları istisnai durum yakalama mekanizmasının çalışması için mutlaka gereklidir. Programımızın hata vermemesi için try blokundan sonra catch ya da finally blokları gelmelidir. Ancak try blokundan sonra finally bloku gelirse istisnai durum yakalama mekanizması çalışmayacağı için böyle bir kullanım tavsiye edilmez.

Hatanın türüne bağlı hata yakalama değiştir

Farkındaysanız şimdiye kadar try blokunda herhangi bir hata gerçekleşmesi durumunda catch blokundaki satırların çalışmasını sağladık. Şimdi hatanın türüne göre farklı catch bloklarının çalıştırılmasını sağlayacağız. Ancak bunun için bazı ön bilgiler almanız gerekiyor.

C#'ta bütün hata türleri System isim alanındaki birer sınıfla temsil edilir, bu sınıflar Exception sınıfından türeyen SystemException sınıfından türer. Programın try blokunda bir hata gerçekleştiği zaman bir hata sınıfı türünden nesne üretilir ve bu nesne catch blokuna parametre olarak gönderilir. Bu süreçte try blokunun yaptığı şeye "hata fırlatma", catch blokunun yaptığı şeye "hata yakalama" denir. Örnek:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          string a=Console.ReadLine();
          string b=Console.ReadLine();
          int toplam=Int32.Parse(a)+Int32.Parse(b);
          Console.WriteLine(toplam);
       }
       catch(FormatException nesne)
       {
          Console.WriteLine("Sayı girmelisiniz!");
       }
    }
 }

System isim alanındaki FormatException metotlara yanlış formatta parametre verilmesiyle ilgilenir. Dolayısıyla da örneğimizde kullanıcı rakam yerine harf girerse Parse() metodu gerekli dönüşümü yapamayacağı için catch bloku çalışacaktır. Başka bir örnek:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          string a=Console.ReadLine();
          string b=Console.ReadLine();
          int toplam=Int32.Parse(a)+Int32.Parse(b);
          Console.WriteLine(toplam);
       }
       catch(FormatException nesne1)
       {
          Console.WriteLine("Sayı girmelisiniz!");
       }
       catch(IndexOutOfRangeException nesne2)
       {
          Console.WriteLine("Dizi sınırları aşıldı!");
       } 
    }
 }

IndexOutOfRangeException dizi sınırlarının aşımıyla ilgilenen bir sınıftır. Gördüğünüz gibi birden fazla catch bloku tasarlayıp oluşan farklı hata tiplerine göre catch bloklarından sadece birinin çalışmasını sağlayabiliyoruz. Başka bir örnek:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          string a=Console.ReadLine();
          string b=Console.ReadLine();
          int toplam=Int32.Parse(a)+Int32.Parse(b);
          Console.WriteLine(toplam);
       }
       catch(FormatException nesne)
       {
          Console.WriteLine("Şu hata meydana geldi: "+nesne.Message);
       }
    }
 }

Hata sınıfları sonuçta bir sınıf olduğuna göre bu sınıfların kendine özgü üye elemanları olmalı. İşte Message özelliği hemen hemen bütün hata sınıflarında bulunur ve hatanın ne olduğunu belirten bir string döndürür (tabii ki İngilizce). Message gibi bütün hata sınıflarında bulunan bazı özellikler daha vardır:

  • Source Hata nesnesinin gönderildiği uygulama ya da dosyanın adıdır. (string)
  • StackTrace Hatanın oluştuğu yer hakkında bilgi verir. (string)
  • HelpLink Hatayla ilgili olan yardım dosyasını saklar. Tabii ki bunu programcı belirler. (string)
  • TargetSite İstisnai durumu fırlatan metot ile ilgili bilgi verir. (MethodBase)
  • InnerException catch bloku içerisinden bir hata fırlatılırsa catch blokuna gelinmesine yol açan istisnai durumun Exception nesnesidir.
  • ToString() Bu metot ilgili hataya ilişkin hata metninin tamamını string olarak döndürür.

Yukarıdaki üye elemanların tamamı static değildir. Şimdi çeşitli örnekler yapalım:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          Metot();
       }
       catch(IndexOutOfRangeException nesne)
       {
          Console.WriteLine("Dizi sınırları aşıldı.");
       }
    }
    static void Metot()
    {
       int[] a=new int[2];
       Console.WriteLine(a[3]);
    }
 }

Bu program ekrana Dizi sınırları aşıldı. yazacaktır. Bu örnekte hatanın asıl oluştuğu yer Metot() metodudur. Ancak Metot() metodunun içinde bu hata yakalanmadığı için Main() metodunun içinde yakalanmıştır.

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          Metot();
       }
       catch(IndexOutOfRangeException nesne)
       {
          Console.WriteLine("Metodu kullananda hata yakalandı");
       }
    }
    static void Metot()
    {
       try
       {
          int[] a=new int[2];
          Console.WriteLine(a[3]);
       }
       catch(IndexOutOfRangeException nesne)
       {
          Console.WriteLine("Metodun kendisinde hata yakalandı.");
       }
    }
 }

Bu program ekrana Metodun kendisinde hata yakalandı. yazacaktır. Yani daima hatanın gerçekleştiği yere en yakın olan hata yakalama mekanizması çalışır. Başka bir örnek:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          int[] a=new int[2];
          Console.WriteLine(a[3]);
       }
       catch(IndexOutOfRangeException)
       {
          Console.WriteLine("Dizi sınırları aşıldı");
       }
    }
 }

Gördüğünüz gibi catch'e parametre verirken illaki nesne oluşturulmasına gerek yok. Sadece sınıfın adı yazılması yeterli. Ancak tabii ki bu durumda sınıfa ait üye elemanlara erişemeyiz. Başka bir örnek:

 using System;
 class deneme
 {
    static void Main()
    {
       for(;;)
       {
          try
          {
             Console.Write("Lütfen çıkmak için 0 ya da 1 girin: ");
             int a=Int32.Parse(Console.ReadLine());
             int[] dizi=new int[2];
             Console.WriteLine(dizi[a]);
             break;
          }
          catch
          {
             continue;
          }
       }
    }
 }

Bu programda istisnai durum mekanizmasını son derece yaratıcı bir şekilde kullandık. Programı biraz inceleyince ne yapmak istediğimizi anlayacaksınız.

NOT: Elbetteki try blokunun içinde bir hata fırlatıldığı zaman try blokunun geri kalan komutları çalıştırılmaz. Akış direkt catch blokuna yönlendirilir.

throw anahtar sözcüğü değiştir

Aşağıdaki programı tekrar göz önüne alalım:

using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          string a=Console.ReadLine();
          string b=Console.ReadLine();
          int toplam=Int32.Parse(a)+Int32.Parse(b);
          Console.WriteLine(toplam);
       }
       catch
       {
          Console.WriteLine("Sayı girmelisiniz!");
       }
    }
 }

Bu programda aslında hatayı fırlatan Int32 yapısındaki Parse() metodudur. Ancak bu metot içinde bu hata yakalanmadığı için bu metodu çağıran Main() metodunda yakalanmıştır. Şimdiye kadar fırlatılan hatayı yakalamakla ilgilendik, şimdi kendimiz de hata fırlatabileceğiz. Hata fırlatmak için throw anahtar sözcüğünü kullanırız. Bu anahtar sözcük bir hata nesnesi fırlatmalıdır. Bir hata nesnesi throw anahtar sözcüğü yardımıyla şöyle fırlatılabilir:

 throw new IndexOutOfRangeException("Dizinin sınırları aşıldı");

veya

 IndexOutOfRangeException nesne=new IndexOutOfRangeException("Dizinin sınırları aşıldı");
 throw nesne;

Birincisinde Message özelliğinin değeri "Dizinin sınırları aşıldı" stringi olan yeni bir IndexOutOfRangeException nesnesi fırlatılıyor. İkincisinde ise önce nesne oluşturuluyor sonra bu nesne fırlatılıyor. Nesne oluşturulurken yapıcı metot kullanılıyor. Şimdi bunları az önceki üzerinde görelim:

 using System;
 class deneme
 {
    static void Main()
    {
       for(;;)
       {
          try
          {
             Console.Write("Lütfen çıkmak için 0 ya da 1 girin: ");
             string a=Console.ReadLine();
             if(a=="0"||a=="1")
                break;
             else
                throw new IndexOutOfRangeException("Devam ediliyor");
          }
          catch(IndexOutOfRangeException nesne)
          {
             Console.WriteLine(nesne.Message);
             continue;
          }
       }
    }
 }

Şimdi aynı örneği throw anahtar sözcüğünün değişik formuyla yapalım:

 using System;
 class deneme
 {
    static void Main()
    {
       for(;;)
       {
          try
          {
             Console.Write("Lütfen çıkmak için 0 ya da 1 girin: ");
             string a=Console.ReadLine();
             if(a=="0"||a=="1")
                break;
             else
             {
                IndexOutOfRangeException nesne=new IndexOutOfRangeException("Başa dönüldü");
                nesne.HelpLink="http://tr.wikibooks.org"; //Gördüğünüz gibi bu yöntemle nesnenin özelliklerini değiştirebiliyoruz.
                throw nesne;
             }
          }
          catch(IndexOutOfRangeException nesne)
          {
             Console.WriteLine(nesne.Message);
             Console.WriteLine("Ek yardım için {0} adresini kullanın.",nesne.HelpLink);
             continue;
          }
       }
    }
 }

İstisnai durum sınıflarında türeme değiştir

Aslında bütün istisnai durum sınıfları Exception sınıfından türetilmiştir. Ancak Exception sınıfındaki üye elemanlar sanal olarak bildirilmiş ve istisnai durum sınıfları da bu üye elemanları override etmiştir. Benzer şekilde çoklu türetmenin yapıldığı sınıflar da mevcuttur. Örneğin:

  • SystemException sınıfı Exception sınıfından türemiştir.
  • IOException sınıfı SystemException sınıfından türemiştir.
  • FileNotFoundException sınıfı IOException sınıfından türemiştir.

Kalıtım konusunda da gördüğümüz gibi yavru sınıf nesneleri ana sınıf nesneleri yerine kullanılabilir. Dolayısıyla bir catch bloku IOException hatalarını yakalıyorsa aynı zamanda FileNotFoundException hatalarını da yakalar. Ancak tabii ki hem IOException hem de FileNotFoundException catch'leri oluşturulmuşsa FileNotFoundException'ın catch'i çalıştırılacaktır.
NOT1: Birden fazla catch bloku oluşturduğumuz durumlarda catch blokları art arda gelmelidir. Yani araya herhangi başka kod giremez.
NOT2: Bir C# programında aşağıdaki iki catch bloku varsa ikincisi (parametreli olan) çalışır.

 catch
 {
 }
 catch(Exception nesne)
 {
 }

Ancak başka dillerden alınmış bir COM parçacığı söz konusuysa birincisi çalışır. COM parçacıkları çok ayrıntılı ve karmaşık olduğundan ve muhtemelen işiniz düşmeyeceğinden birinci olasılığı özümsemeniz yeterlidir.
NOT3: Birden fazla art arda gelen catch blokunun parametreleri aynıysa programımız derlenmez.

İç içe geçmiş try blokları değiştir

try-catch-finally yapımızın şöyle olduğunu düşünelim:

 try
 {
    //A
    try
    {
       //B
    }
    catch(ExceptionSinifi1 es1)
    {
       //C
       //İçteki catch bloku
    }
    catch(ExceptionSinifi2 es2){}
    finally
    {
       //D
       //İçteki finally bloku
    }
 }
 catch
 {
    //Dıştaki catch bloku
 }
 finally
 {
    //Dıştaki finally bloku
 }

Hatanın fırlatıldığı yere bağlı olarak çalışacak bloklar şöyledir:

  1. A bölgesinden bir hata fırlatıldığı zaman dıştaki catch bloku ve dıştaki finally bloku çalışır, içteki finally bloku çalışmaz.
  2. B bölgesinden bir hata fırlatıldığı zaman önce içteki catch bloklarına bakılır. Aynı tür varsa bu catch bloku çalıştırılır, aynı tür yoksa bilinçsiz tür dönüşümünün olup olmadığına bakılır. Birden fazla bilinçsiz tür dönüşümünün mümkün olduğu catch bloku varsa türetme zincirindeki daha yavru olan türlü catch bloku çalışır. Uygun tür yoksa dıştaki catch bloku çalıştırılır. B bölgesinde oluşan hata içerideki catch bloklarından yakalansın veya yakalanmasın içteki finally bloku çalışır.
  3. C veya D bölgesinden bir hata fırlatıldığı zaman dıştaki catch bloku tarafından yakalanır ve dıştaki finally bloku çalışır, içteki finally bloku çalışmaz.
  4. Benzer kurallar ikiden fazla iç içe geçmiş try blokları için de geçerlidir. Yani uygun tür varsa en içteki try blokundaki hata en içteki catch tarafından yakalanır. Uygun tür yoksa basamak basamak dışa çıkılır.
  5. Hiç hata oluşmaması durumunda her iki finally bloku da çalışır.
  6. Dıştaki finally bloku her durumda çalışır.
  7. finally bloklarının çalışıp çalışmaması hatanın yakalanıp yakalanmamasına bağlı değildir. Sadece hatanın nerede oluştuğuna bağlıdır. B bölgesinde oluşan hatalarda hem içteki hem de dıştaki finally blokları çalışır. B bölgesi dışında ama dışarıdaki try bloku içinde oluşan hatalarda sadece dışarıdaki finally bloku çalışır.

İstisnai durum sınıfları değiştir

Şimdiye kadar birkaç istisnai durum sınıfı gördük. Şimdi bunları ve sık kullanılan birkaç sınıfı daha göreceğiz:

  • System.OutOfMemoryException Programın çalışması için yeterli bellek kalmadıysa fırlatılır.
  • System.StackOverflowException Stack bellek bölgesinde yeterli alan kalmadıysa kullanılır. Kendini sonsuza kadar çağıran metot bu hatayı meydana getirir.
  • System.NullReferenceException Bellekte yer ayrılmamış bir nesne üzerinden sınıfın üye elemanlarına erişmeye çalışırken fırlatılır.
  • System.OverflowException Bir veri türüne kapasitesinden fazla veri yüklemeye çalışılırken fırlatılır.
  • System.InvalidCastException Tür dönüştürme operatörüyle geçersiz tür dönüşümü yapılmaya çalışıldığında fırlatılır.
  • System.IndexOutOfRangeException Bir dizinin olmayan elemanına erişilmeye çalışılırken fırlatılır.
  • System.ArrayTypeMismatchException Bir dizinin elemanına yanlış türde veri atanmaya çalışılırken fırlatılır.
  • System.DividedByZero Sıfıra bölme yapıldığı zaman fırlatılır.
  • System.ArithmeticException DividedByZero ve OverflowException bu sınıftan türemiştir. Hemen hemen matematikle ilgili tüm istisnaları yakalayabilir.
  • System.FormatException Metotlara yanlış formatta parametre verildiğinde fırlatılır.

Bu sınıfların tamamı Exception sınıfından türeyen SystemException sınıfından türer.

Kendi istisnai durum sınıflarımızı oluşturmak değiştir

.Net Framework kütüphanesinde onlarca istisnai durum sınıfı vardır. Ancak istersek kendi istisnai durum sınıflarımızı da oluşturabiliriz. Kendi oluşturduğumuz sınıfları ApplicationException sınıfından türetiriz. Bu sınıf Exception sınıfından türemiştir. Dolayısıyla kendi oluşturduğumuz istisnai durum sınıflarına da Exception sınıfındaki Message, HelpLink gibi üye elemanlar otomatik olarak gelecektir. Bu üye elemanları istersek override edebilir, istersek olduğu gibi bırakabiliriz. İstersek de kendi üye elemanlarımızı yazabiliriz. İsterseniz şimdi örneğimize başlayalım. Örneğimizde öğrencilerin notlarını tutan bir sınıf tasarlayalım. Sonra bu sınıfın içinde iki tane hata sınıfı oluşturalım. Birinci sınıf öğrencinin notu 100'den büyükse, ikinci sınıf 0'dan küçükse hata verdirsin. Şimdi örneğimize başlayabiliriz:

 using System;
 class Notlar
 {
    private int mNot;
    public int Not
    {
       get{return mNot;}
       set
       {
          if(value>100)
             throw new FazlaNotHatasi();
          else if(value<0)
             throw new DusukNotHatasi();
          else
             mNot=value;
       }
    } 
    public class FazlaNotHatasi:ApplicationException
    {
       override public string Message
       {
          get{return "Not 100'den büyük olamaz.";}
       }
    }
    public class DusukNotHatasi:ApplicationException
    {
       override public string Message
       {
          get{return "Not 0'dan küçük olamaz.";}
       }
    }
 }
 class Ana
 {
    static void Main()
    {
       try
       {
          Notlar a=new Notlar();
          Console.Write("Not girin: ");
          int b=Int32.Parse(Console.ReadLine());
          a.Not=b;
          Console.WriteLine("Notunuzu başarıyla girdiniz.");
       }
       catch(Exception nesne)
       {
          Console.WriteLine(nesne.Message);
       }
    }
 }

Programı inceleyince muhtemelen kendi istisnai durum sınıflarımızı nasıl yaptığımızı anlayacaksınız. Ancak yine de özet bir bilgi vermek istiyorum. Hata sınıf(lar)ımızı asıl sınıfımızın içine koyuyoruz. Asıl sınıfımız içinde herhangi bir anda bu hata sınıflarımız türünden nesne fırlatabiliyoruz. Ayrıca bu programdaki catch'in Exception türünden nesne alması, ancak bu nesne üzerinden yavru sınıfa ait özelliğe erişilmesi geçen bölümde gördüğümüz sanal üye elemanlara çok iyi bir örnek. Şimdi örneğimizi biraz değiştirelim:

 using System;
 class Notlar
 {
    //Buraya az önceki Notlar sınıfının aynısı gelecek.
 }
 class Ana
 {
    static void Main()
    {
       try
       {
          Notlar a=new Notlar();
          Console.Write("Not girin: ");
          int b=Int32.Parse(Console.ReadLine());
          a.Not=b;
          Console.WriteLine("Notunuzu başarıyla girdiniz.");
       }
       catch(Notlar.FazlaNotHatasi nesne)
       {
          Console.WriteLine(nesne.Message);
       }
    }
 }

Bu programda fazla not hataları yakalanacak ancak düşük not hataları yakalanmayacaktır. Eğer düşük not hatası oluşursa program çalışma zamanında şunun gibi bir uyarı verip kendini sonlandıracaktır.

Unhandled Exception: Notlar+DusukNotHatasi: Not 0'dan küçük olamaz.
   at Notlar.set_Not(Int32 value)
   at Ana.Main()

Buradan hata fırlattıran sınıfın Notlar sınıfındaki DusukNotHatasi sınıfı olduğunu, bu sınıfa ait Message özelliğinin değerinin "Not 0'dan küçük olamaz." olduğunu, hatanın Notlar sınıfındaki Not sahte özelliğine Int32 türünden veri atanırken oluştuğunu ve son tahlilde hatanın Ana sınıfındaki Main() metodunda çalışılırken oluştuğunu anlıyoruz. Şimdi şöyle basit bir örnek yapalım:

 using System;
 class deneme
 {
    static void Main()
    {
       int a=Int32.Parse(Console.ReadLine());
       Console.WriteLine(3/a);
    }
 }

Kullanıcının bu programda 0 girdiğini varsayarsak program çalışma zamanı hatasında şöyle bir çıktı verir:

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at deneme.Main()

Buradan hata fırlattıran sınıfın System isim alanındaki DivideByZeroException sınıfı olduğunu, bu sınıfın Message özelliğinin değerinin "Attempted to divide by zero." olduğunu ve hatanın deneme sınıfındaki Main() metodunda oluştuğunu anlıyoruz. Benzer şekilde çalışarak yeni hata sınıfları keşfedebilirsiniz.
NOT: Hatayı yakalayan birden fazla catch bloku varsa ve bu catch bloklarının parametreleri arasında türeme varsa bu durumda catch bloklarının sıralamasının yavru sınıftan ana sınıfa doğru olması gerekir. Örneğin şu program derleme zamanı hatası verir:

 using System;
 class deneme
 {
    static void Main()
    {
       try
       {
          int a=Int32.Parse(Console.ReadLine());
          Console.WriteLine(3/a);
       }
       catch(Exception nesne)
       {
          Console.WriteLine("Hata var!");
       }
       catch(DivideByZeroException nesne)
       {
          Console.WriteLine("Hata var!");
       }
    }
 }

NOT: .Net kütüphanesindeki istisnai durum sınıflarının yapıcı metodu bir parametre alıyordu ve bu parametrede ilgili nesnenin Message özelliğinin değeri belirleniyordu. Tabii ki siz de kendi istisnai durum sınıflarınızın yapıcı metodu olmasını ve istediğiniz sayıda parametre almasını sağlayabilirsiniz.

NOT: try-catch ikilisiyle bir istisnai durum yakalanmadığı zaman ekrana yazılan hata yazısı ilgili istisnai durum sınıfının ToString() metodunun ürettiği değerdir. Kendi istisnai durum sınıflarımızda bu metodu override ederek yakalanmayan hatalarda ekrana çıkacak yazıyı değiştirebiliriz.

NOT: Hata sınıflarımızı asıl sınıfımızın içine koymak zorunda değiliz. Ancak eğer asıl sınıfımızın içine koyarsak ve erişim belirleyicisini private yaparsak bu sınıfın ismine programımız içinde atıfta bulunamayız. Ancak halen bu sınıf türünden fırlatılan nesneyi Exception nesnesi olarak ele alıp hata sınıfımızın Exception sınıfından devraldığı üye elemanlarına erişebiliriz, ancak hata sınıfımızın kendi yazdığı üye elemanlara erişemeyiz.

İstisna filtreleme değiştir

6.0 sürümünden beri C# programlama dilinde catch blokları aynı türde parametre alabiliyor. Ancak bu durumda catch bloklarına ek düzenleme yapmamız gerekiyor. örnek:

using System;
class HataSinifi:ApplicationException
{
    public bool KritikMi=true;
}
class Sinif
{
    public static void Metot()
    {
        throw new HataSinifi { KritikMi = false };
    }
}
class AnaSinif
{
    static void Main()
    {
        try{Sinif.Metot();}
        catch(HataSinifi hs) when (hs.KritikMi) { Console.WriteLine("Kritik hata oluştu"); }
        catch(HataSinifi hs) when (!hs.KritikMi) { Console.WriteLine("Kritik olmayan hata oluştu."); }
    }
}

Gördüğünüz gibi iki catch bloku da aynı tipte parametre almasına rağmen eklenen when deyimiyle fırlatılan nesnenin bir özelliğinin değerine göre catch bloklarından sadece birinin çalışması sağlanıyor. İstenirse tek catch bloku olması durumunda da bu yöntem kullanılabilir. Örneğin bu sayede sadece kritik hataların yakalanması, kritik olmayan hataların yakalanmaması sağlanabilir. Burada when deyiminin parantezleri içindeki ifadenin illaki hata nesnesi üzerinde işlem yapmasına gerek yoktur, bool nesne döndürmesi yeterlidir. İkisi de true döndürürse birincisi çalışır. İkisi de false döndürürse hiçbiri çalışmaz (hata yakalanmaz).

Bu kitabın diğer sayfaları
  • Sınıflar
  • Operatör aşırı yükleme
  • İndeksleyiciler
  • Yapılar
  • Enum sabitleri
  • İsim alanları
  • System isim alanı
  • Temel I/O işlemleri
  • Temel string işlemleri
  • Kalıtım
  • Arayüzler
  • Partial (kısmi) tipler
  • İstisnai durum yakalama mekanizması
  • Temsilciler
  • Olaylar
  • Önişlemci komutları
  • Göstericiler
  • Assembly kavramı
  • Yansıma
  • Nitelikler
  • Örnekler
  • Şablon tipler
  • Koleksiyonlar
  • yield
  • Veri tabanı işlemleri
  • XML işlemleri
  • Form tabanlı uygulamalar
  • Visual Studio.NET
  • Çok kanallı uygulamalar
  • ASP.NET