C# Hata Denetimi (try, catch, finally)
C#’ta try, catch ve finally bloklarını kullanarak hataları yakalamayı ve güvenli hata yönetimi yapmayı örneklerle öğrenin.
C#’ta hata denetimi, program çalışırken oluşabilecek beklenmedik durumları yakalayıp kontrol altına almak için kullanılır.
Bu sayede program aniden çökmez, kullanıcıya uygun mesaj verilebilir veya alternatif bir yol izlenebilir.
Hata yönetiminde try, catch ve finally blokları birlikte kullanılır.
try-catch Kullanımı
try bloğu içinde hataya yol açabilecek kodlar yazılır. Eğer bir hata (exception) oluşursa catch bloğu devreye girer.
try
{
int sayi = int.Parse("abc"); // Geçersiz dönüşüm
Console.WriteLine("Sayı: " + sayi);
}
catch (FormatException ex)
{
Console.WriteLine("Hata: Geçersiz sayı formatı.");
}
// Çıktı:
Hata: Geçersiz sayı formatı.
Birden Fazla catch
Farklı hata türleri için birden fazla catch kullanılabilir.
Bu sayede her hataya özel çözüm uygulanabilir.
try
{
int[] sayilar = { 1, 2, 3 };
Console.WriteLine(sayilar[5]); // Dizi taşması
}
catch (IndexOutOfRangeException)
{
Console.WriteLine("Hata: Dizi sınırları aşıldı.");
}
catch (Exception ex)
{
Console.WriteLine("Beklenmeyen hata: " + ex.Message);
}
İleri Seviye Hata Yönetimi: Exception Filters (when)
C# dilinde exception filter (istisna filtresi),
catch bloğuna when anahtar kelimesi ile
bir koşul eklemenizi sağlar.
Böylece bir istisna (exception) yalnızca belirli bir koşul sağlandığında yakalanabilir.
Exception filter’ın en önemli avantajı, koşulun
catch bloğuna girilmeden önce değerlendirilmesidir.
Eğer koşul false dönerse, runtime o catch bloğunu atlar
ve uygun başka bir catch bloğu aramaya devam eder.
Bu yaklaşım sayesinde:
- Daha temiz ve okunabilir hata yönetimi sağlanır
- Exception kontrolü daha hassas şekilde yapılır
- Catch blokları içinde gereksiz
ifyapıları yazma ihtiyacı azalır
Örnek: HTTP Hatalarını Status Code’a Göre Yönetmek
Gerçek dünya uygulamalarında HTTP istekleri farklı durum kodları (status code) döndürebilir. Exception filter kullanarak belirli durum kodlarını ayrı ayrı ele alabilir, kodun yapısını daha düzenli ve okunabilir tutabiliriz.
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
try
{
HttpResponseMessage response =
await client.GetAsync("https://api.example.com/users/1");
response.EnsureSuccessStatusCode();
string content = await response.Content.ReadAsStringAsync();
Console.WriteLine(content);
}
catch (HttpRequestException ex)
when (ex.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine("Kaynak bulunamadı (404).");
}
catch (HttpRequestException ex)
when (ex.StatusCode == HttpStatusCode.Unauthorized)
{
Console.WriteLine("Yetkisiz erişim (401). Kimlik bilgilerinizi kontrol edin.");
}
catch (HttpRequestException ex)
{
Console.WriteLine("Genel bir HTTP hatası oluştu.");
Console.WriteLine($"Durum Kodu: {ex.StatusCode}");
}
}
}
Bu örnekte:
- API
404 Not Founddönerse özel bir mesaj gösterilir. - API
401 Unauthorizeddönerse ayrı bir şekilde ele alınır. - Diğer HTTP hataları genel
HttpRequestExceptionbloğunda yakalanır.
whenkoşulu,catchbloğuna girilmeden önce değerlendirilir.- Koşul
falseise runtime ilgilicatchbloğunu atlar. - Exception filter özelliği C# 6 ile birlikte gelmiştir ve modern backend geliştirmede yaygın olarak kullanılır.
Rethrowing Exceptions: throw; vs throw ex;
Bir catch bloğu içinde yakalanan bir exception tekrar fırlatılmak istenebilir.
Ancak throw; ve throw ex; aynı davranışı göstermez.
Aralarındaki temel fark, stack trace bilgisinin korunup korunmamasıdır. Stack trace, hatanın hangi metot zinciri üzerinden geldiğini ve tam olarak hangi satırda oluştuğunu gösterir.
-
throw;Hatanın asıl kaynağını (satır numarasını ve oluştuğu metodu) koruyarak hatayı yukarı fırlatır. Hata ayıklama (debugging) sırasında hatanın gerçekten nerede başladığını görebilirsin. En doğru ve önerilen yöntem budur. -
throw ex;Stack trace bilgisini o satırda sıfırlar ve sanki hata ilgilicatchbloğunda oluşmuş gibi davranır. Bu durumda hatanın gerçek kaynağı (örneğin daha derindeki bir metot) kaybolur ve hata ayıklama zorlaşır.
Örnek
using System;
class Program
{
static void Main()
{
try
{
MethodA();
}
catch (Exception ex)
{
Console.WriteLine("Hata loglandı.");
// Doğru kullanım:
throw;
// Yanlış kullanım:
// throw ex;
}
}
static void MethodA()
{
MethodB();
}
static void MethodB()
{
throw new InvalidOperationException("Bir hata oluştu.");
}
}
Bu örnekte throw; kullanılırsa hata, MethodB içinde
başladığı şekilde stack trace içerisinde görünür.
Eğer throw ex; kullanılırsa, hata catch bloğundan
başlamış gibi görünür ve orijinal çağrı zinciri kaybolur.
- Exception yeniden fırlatılacaksa her zaman
throw;tercih edilmelidir. throw ex;hata ayıklamayı zorlaştırır çünkü stack trace bilgisini bozar.throwanahtar kelimesi ile custom exception sınıfları da fırlatılabilir.
Custom Exceptions (Özel Exception Sınıfları)
Gerçek dünya uygulamalarında her hata Exception ya da diğer genel exception türleri ile ifade edilmemelidir.
İş kurallarına (business logic) özel durumları daha anlamlı ve yönetilebilir hale getirmek için custom exception sınıfları oluşturulabilir.
Bu yaklaşım:
- Hata tiplerini daha net ayırmayı sağlar
- Catch bloklarında daha spesifik yakalama imkanı sunar
- Loglama ve hata analizinde daha fazla bağlamsal bilgi taşır
- Kodun okunabilirliğini ve bakımını kolaylaştırır
Örnek
// 1. Custom exception tanımları
public class ProjectNotFoundException : Exception
{
public ProjectNotFoundException(string message) : base(message) { }
}
public class ProjectIsCanceledException : Exception
{
public int ProjectId { get; }
public string ProjectName { get; }
public ProjectIsCanceledException(int projectId, string projectName)
: base($"Project '{projectName}' (Id: {projectId}) is canceled and cannot be processed.")
{
ProjectId = projectId;
ProjectName = projectName;
}
}
// 2. Kullanımı
public void ProcessProject(Project project)
{
if (project == null)
{
throw new ProjectNotFoundException("Proje sistemde kayıtlı değil.");
}
if (project.Status == ProjectStatus.Canceled)
{
throw new ProjectIsCanceledException(project.Id, project.Name);
}
// ...
}
Bu örnekte sistemde bulunmayan bir proje için
ProjectNotFoundException fırlatılır.
Eğer proje iptal edilmiş durumdaysa,
ProjectIsCanceledException yalnızca bir hata mesajı değil,
aynı zamanda ProjectId ve ProjectName bilgilerini de taşır.
Bu sayede loglama ve hata analizi daha anlamlı hale gelir.
- Custom exception sınıfları genellikle iş kurallarına özel durumları temsil eder.
- İsimlendirme genellikle
SomethingExceptionformatında yapılır. - Ek propertyler eklenerek hata hakkında daha fazla bağlamsal bilgi taşınabilir.
finally Bloğu
finally bloğu, hata olsun veya olmasın her zaman çalıştırılır.
Genellikle dosya kapatma, veritabanı bağlantısı sonlandırma gibi temizleme işlemleri için kullanılır.
try
{
Console.WriteLine("Dosya açılıyor...");
throw new Exception("Dosya bulunamadı!");
}
catch (Exception ex)
{
Console.WriteLine("Hata: " + ex.Message);
}
finally
{
Console.WriteLine("Dosya kapatılıyor...");
}
// Çıktı:
Dosya açılıyor...
Hata: Dosya bulunamadı!
Dosya kapatılıyor...
Özel Exception Fırlatma
Kendi hata koşullarınızı tanımlayıp throw ile hata fırlatabilirsiniz.
static void Bolme(int a, int b)
{
if (b == 0)
throw new DivideByZeroException("Sıfıra bölme hatası!");
Console.WriteLine("Sonuç: " + (a / b));
}
static void Main()
{
try
{
Bolme(10, 0);
}
catch (DivideByZeroException ex)
{
Console.WriteLine("Hata: " + ex.Message);
}
}
// Çıktı:
Hata: Sıfıra bölme hatası!
TL;DR
try: Exception fırlatabilecek kod bloğunu içerir.catch: Exception oluştuğunda hatayı yakalar ve işler.finally: Her zaman çalışır, genellikle temizlik işlemleri için kullanılır.- Birden fazla
catchbloğu, farklı exception türlerini ayrı ayrı ele almayı sağlar. - Exception filters (
when) koşullu exception yakalamaya imkan verir. throw;exception yeniden fırlatılırken orijinal stack trace bilgisini korur.throw ex;stack trace bilgisini sıfırlar ve genellikle kaçınılmalıdır.- Custom exception sınıfları, domain veya iş kuralı hatalarını temsil etmek için kullanılır.
İlişkili Makaleler
C# Döngüler (for, foreach, while, do-while)
C#’ta for, foreach, while ve do-while döngülerinin nasıl kullanıldığını öğrenin. Tekrar eden işlemleri yönetmek için pratik örnekler keşfedin.
C# ile SOLID Prensipleri
C# örnekleriyle SOLID prensiplerinin uygulanışı: daha esnek, sürdürülebilir ve test edilebilir kod tasarımları.
C# Interop (C/C++ Kütüphaneleri ile Çalışma)
C#’ta Interop kullanarak C/C++ kütüphaneleriyle çalışmayı öğrenin. P/Invoke, unmanaged kod ve veri geçişi örneklerle açıklanıyor.
C# Karar Yapıları (if, else, switch)
C#’ta karar yapıları: if, else if, else ve switch ile koşullara göre farklı işlemler yapmayı öğrenin.
C# Metotlar ve Parametre Kullanımı
C#’ta metot tanımlama ve parametre kullanımını öğrenin. Değer ve referans parametreleri, varsayılan parametreler ve örneklerle.