Gelişmiş Try Catch Kontrolü ve Yönetimi

Merhaba Arkadaşlar. Try Catch blokları bir çoğumuzun bildiği gibi yazılım dünyasında oldukça fazla kullanılan ve bir çok noktada hayat kurtarıcı niteliğe sahip olan kod bloklarıdır.

“Try” kısmında yazmış olduğunuz kodların herhangi bir yerinde programınızın kullanıcı hatası veya beklenmeyen bir sistem hatası gibi durumlarda patlamasını önleyip, size durumu bildiren hatalar döndürebilmektedir. Ancak tabii ki bir çok zaman bu kontrolü olduğu gibi kullanmak biraz karmaşıklığa yol açabilmektedir. Bu makalede sizlere anlatmak istediğim konu da bu kontrolü kendi kontrolümüzde nasıl kullanabileceğimizdir. (Ne çok kontrol dedim değil mi? 🙂 )

Öncelikle basit ve temel kullanılışına bir örnek vererek başlayalım. Standart olarak aşağıdaki gibi bir parse işleminde try catch kontrolünü kullanmamız mümkün.

string giris = TextBox1.Text;
int sonuc = 0;

try
{
    sonuc = int.Parse(giris);
}
catch (Exception)
{
    throw;
}

Burada kullanıcının TextBox1 kutusuna girdiği değer eğer bir sayı ise ve bu sayı da integer’a çevrilebilir bir sayı ise (-2.147.483.647 ila +2.147.483.647 aralığı) kodumuz düzgün çalışacak ve integer çevirme olayını başarılı bir şekilde tamamlayacaktır. Peki ya bu değer bir “ahmet” olarak girilir ise? İşte bu durumda kodumuz patlayacak ve bize aşağıdaki gibi bir hata fırlatacaktır.

System.FormatException: ‘Giriş dizesi doğru biçimde değildi.’

Bunun sonucu olarak programımız patlamış olacak. Peki neden? Hani Try Catch blokları programın patlamasını engelliyordu? Hani program patlamayacaktı!

Öncelikle bunu ortadan kaldırmak için “catch” bloğundaki “throw;” cümleciğini kaldırmamız gerekli. Çünkü “throw” fırlatmak anlamına gelir. Yani kısaca biz bu kelimeyi burada bırakarak programımıza zaten bir hata olursa bunu “throw” (yani fırlat) demiş oluyoruz. Peki bu durumu nasıl ortadan kaldırabiliriz? Gelin aşağıda try / catch’i en doğru şekilde nasıl kullanabileceğimizi bir kaç örnek ile anlatalım. (Ancak her yiğidin yoğurt yiyişi ayrıdır demeden geçmek istemiyorum. Elbette sizler çok daha etkili yollar da bulabilirsiniz kendinize. Eğer isterseniz bunları yorumlar kısmında bizlerle de paylaşabilirsiniz.)

Try Catch En Doğru Kullanım Şekilleri Nelerdir?

1) Özelleştirilmiş Hatalar Göstermek

Burada altını çizmek isterim ki, eğer alınan hatanın ne olduğundan emin iseniz bu yöntemi kullanın. Aksi taktirde mutlaka ikinci maddede belirttiğim şekilde log almaktan kaçmayın.

Özelleştirilmiş hata ne demektir? Özellikle şunu da belirteyim, bu durumda da programınız patlayacaktır. Ancak patlayan programınızda kullanıcı asıl hatayı (örn. object reference not set to an instance of an object) görmeyecek, sadece sizin cümleniz ile karşılaşacak ve programınız kapanacak veya hata sayfası görünecektir. (Buradaki kurgu size kalmış)

Kodumuz da aşağıdaki gibi;

string giris = TextBox1.Text;
int sonuc = 0;

try
{
    sonuc = int.Parse(giris);
}
catch (Exception exc)
{
    throw new Exception("Yaşınızı yalnızca rakamlar ile girmediğiniz için programda hata oluştu!");
}

Gördüğünüz gibi artık kullanıcı hata alacak ancak bu hatayı sadece “Yaşınızı yalnızca rakamlar ile girmediğiniz için programda hata oluştu!” şeklinde görecektir ve programınız kapatılacaktır. Tabii ki bu da çok istenmeyen bir yöntem. Ama yazının biraz aşağısında iç içe try catch kullanımı kısmında bunun da neden işimize yarayabileceğini görüyor olacağız.

2) Loglama Yapmak

Loglama yaparak kullanıcıya özelleştirilmiş bir cümle halinde hatayı bildirip arka planda doğru hata cümlesini siz log olarak kayıt altına alabilirsiniz. Tabi burada logu nerede tutmak istediğiniz tamamen sizin kararınız. İster MSSQL, MySQL veya Herhangi bir NoSQL DB’de, isterseniz de bir TXT dosyasında bu logları tutabilirsiniz. Ancak elbette benim tavsiyem kesinlikle txt’de tutmamanız yönünde olacaktır. Tabi eğer son kullanıcıya açık ve az ya da çok trafikli bir proje çalıştırıyorsanız. Çünkü txt’ye yazma işlemi, işlem adedi çok olduğunda ve bu işlemler aynı zamanda gerçekleşmek istediğinde direk patlayacaktır. Ayrıca tabii ki bir süre sonra TXT boyutu MB’lara hatta GB’lara ulaşacağından sizin açmanız bile imkansız hale gelebilir.

Hatayı loglamadan sadece anlaşılır cümlelerle kullanıcıya göstermek de çoğu zaman yazılımcıyı zor duruma sokar. Özellikle bu hata birden çok kez gerçekleşir ise bu durumda kendisine durumu soran kullanıcıya bir yanıt veremez. Çünkü ortada yazılımcının görebileceği bir hata yoktur. Bu yüzden log tutmak ve bunları daha sonradan arandığında rahat bulunabilecek şekilde tutmak da oldukça önemlidir.

Peki örnek olarak nasıl bir loglama yapabiliriz? Projemizin bir Windows Form Application olduğunu düşünerek aşağıdaki gibi bir kod ve loglama örneği işimizi görecektir.

string giris = TextBox1.Text;
int sonuc = 0;

try
{
    sonuc = int.Parse(giris);
}
catch (Exception exc)
{
    LogYazdir(DateTime.Now, giris, exc.Message);
    MessageBox.Show("Hata!", "İşlem sırasında beklenmeyen bir hata oluştu. Lütfen girdiğiniz değerleri kontrol ederek tekrar deneyin.");
}

Gördüğünüz gibi kullanıcıya çaktırmadan hatayı absorbe ederek logladık. Ancak kullanıcıya da hatanın olabileceği yeri bildiğimiz veya tahmin edebildiğimiz için onun anlayabileceği bir cümle ile hata döndük. Aslında en olası ve istenen tabloda budur. Zira programımız patlamadı. Kullanıcı programdan atılmadı ve sadece bir mesaj ile aynı sayfa karşısında duracak ve şansını tekrar deneyecek şekilde kullanım devam edebiliyor.

İç İçe Try Catch Kullanımı

Diyelim ki biraz uzun bir kodumuz var ve tabii ki birden fazla hata alabileceğimiz nokta söz konusu. Bu durumda birden fazla try catch kullanmamız gerekebilir. Peki buradaki herhangi bir işlemin gerçekleşememesi durumunda hata alınmasını ve işlemin durdurulmasını istiyor isek ne yapabiliriz?

İşte iç içe try catch kullanımı da burada karşımıza çıkıyor. Tabi ben anlaşılır olması adına birden fazla textbox üzerinden gelebilecek hatalar olarak örnekleyeceğim. Ancak siz mutlaka daha kompleks yerlerde kullanabilirsiniz. Zira o tip projelerim de söz konusu ancak onları paylaşmak için bütün projeyi açıklayarak ilerlemem gerekir. O yüzden biraz basitleştirmek adına birden fazla input ile kodumuz aşağıdaki gibi olabilir.

string yasi = txtYasi.Text;
string dogumTarihi = txtDogumTarihi.Text;
string TCKimlikNumarasi = txtTCKimlikNumarasi.Text;

int _yasi, _dogumTarihi, _TCKimlikNumarasi;

try
{
    try
    {
        _yasi = int.Parse(yasi);
    }
    catch (Exception exc1)
    {

       throw;
    }

    try
    {
        _dogumTarihi = int.Parse(dogumTarihi);
    }
    catch (Exception exc2)
    {

       throw;
    }

    try
    {
        _TCKimlikNumarasi = int.Parse(TCKimlikNumarasi);
    }
    catch (Exception exc3)
    {

       throw;
    }
}
catch (Exception exc)
{

       throw;
}

Gördüğünüz gibi burada her bir kontrolün üstünde bir tane daha ve hepsini kapsayan bir try catch bloğumuz var. Peki neden? Aslında konu çok basit. Eğer bu kontrollerin herhangi birinde bir hata olur ise işlemin tümden iptal olmasını ve devam etmemesini istiyoruz. Bu durumu sağlamak için de böyle bir hata kontrolü kullandık. Peki her noktada log kodunu yazmak zorunda mıyız? Elbette hayır. Zaten iç içe kullanmamızın sebebi de bu. Kodumuzu tek bir noktadan loglayabilecek ve özelleştirebilecek şekilde aşağıdaki gibi kullanmamız en doğrusu olacaktır.

string yasi = txtYasi.Text;
string dogumTarihi = txtDogumTarihi.Text;
string TCKimlikNumarasi = txtTCKimlikNumarasi.Text;

int _yasi, _dogumTarihi, _TCKimlikNumarasi;

try
{
    try
    {
        _yasi = int.Parse(yasi);
    }
    catch (Exception exc1)
    {
        throw new Exception(string.Format("{0} - {1}", "Yaş giriş hatası", exc1.Message));
    }

    try
    {
        _dogumTarihi = int.Parse(dogumTarihi);
    }
    catch (Exception exc1)
    {
        throw new Exception(string.Format("{0} - {1}", "Doğum günü giriş hatası", exc1.Message));
    }

    try
    {
        _TCKimlikNumarasi = int.Parse(TCKimlikNumarasi);
    }
    catch (Exception exc1)
    {
        throw new Exception(string.Format("{0} - {1}", "TC kimlik giriş hatası", exc1.Message));
    }
}
catch (Exception exc)
{
    LogYazdir(DateTime.Now, exc.Message);
    MessageBox.Show("Hata!", "Girilen değerlerin bir veya bir kaçında problem söz konusu. Lütfen kontrol ederek tekrar deneyin!");
}

Gördüğünüz gibi burada;

throw new Exception(string.Format("{0} - {1}", "Doğum günü giriş hatası", exc1.Message));

Diyerek hem o bloktaki hatanın orijinal halini aldık hem de yanına hatanın hangi blokta olduğunu da not etmiş olduk. Böylece tek noktadan hata yönetimi yaparak birden fazla log satırı yazmaktan da kurtulmuş olduk. Zaten en üstteki try catch bloğunda olabilecek bir hata bile işlemi tümden sonlandırmamıza yeteceği için de throw şeklinde koddan çıkarak hatayı üst bloğa fırlatarak oradan hatayı yakaladık ve logladık. Tabi aynı zamanda da kullanıcıya onun da anlayabileceği bir şekilde hata gösterdik. Ancak programımız hala ayakta ve kapanmış değil.

Özellikle burada bu konudan basit kodlarla anlatarak ilerlemek istedim ki bir kafa karışıklığına mahal vermeyeyim istedim.

Eğer sorularınız var ise lütfen yorumlar kısmında sormaktan çekinmeyin. Herkese kolaylıklar diliyorum…

3.7 3 votes
Article Rating
Subscribe
Bildir
guest
0 Yorum
Inline Feedbacks
View all comments