İstisnaları yakalamak hata yönetiminin yarısıdır; diğer yarısı doğru olanı fırlatmaktır. İyi seçilmiş bir istisna çağırana tam olarak neyin yanlış gittiğini ve bunun onların hatası mı yoksa programın durumu mu olduğunu söyler. Bu sayfa fırlatma tarafını ele alır; try catch ele almayı kapsar.
throw ifadesi ve koruma cümleleri
throw bir istisna nesnesi alır. Metodun çalışması orada durur ve istisna çağrı yığınında yukarıda bir işleyici arar. En yaygın kullanım bir koruma cümlesidir: bir metodun başında, herhangi bir iş yapılmadan önce geçersiz girdiyi reddeden kontroller.
Çıktı:
ArgumentOutOfRangeException for parameter 'amount'
InvalidOperationException: The account is frozen.
Balance: 100
nameof(amount) "amount" string'ini üretir ve parametre yeniden adlandırılırsa doğru kalır. Argüman istisnaları onu, araçların ve log'ların hatalı argümanı göstermek için kullandığı ParamName'de saklar.
Koruma cümleleri metodun geri kalanını basit tutar: kontrollerden sonra kod geçerli girdiyi varsayabilir. Ayrıca hatalı bir değerin ilerleyip üç metot sonra kafa karıştırıcı bir NullReferenceException'a yol açmasına izin vermek yerine hatanın olduğu noktada başarısız olurlar.
Hangi istisna tipi fırlatılmalı
Durumu tanımlıyorsa yerleşik bir tipi yeniden kullanın; çağıranlar onu nasıl ele alacaklarını zaten bilir.
| Durum | Fırlatın |
|---|---|
Zorunlu bir argüman null | ArgumentNullException |
| Bir argüman izin verilen aralığın dışında (negatif miktar, sonu aşan indeks) | ArgumentOutOfRangeException |
| Bir argüman başka bir şekilde geçersiz (boş ad, hatalı biçimli ID) | ArgumentException |
| Çağrı nesnenin geçerli durumunda geçerli değil | InvalidOperationException |
İşlem bu tip tarafından hiç desteklenmiyor (salt okunur bir koleksiyonun Add'i) | NotSupportedException |
| Metot henüz yazılmadı | NotImplementedException |
Bir nesne Dispose'tan sonra kullanıldı | ObjectDisposedException |
| Zamanlı bir işlemin süresi doldu | TimeoutException |
İlk üç satır ile InvalidOperationException arasındaki çizgi, neyi kimin değiştirmesi gerektiğidir. Bir argüman istisnası "bunu farklı çağır" der. InvalidOperationException "çağrı sorunsuzdu, ama şimdi değil" der.
Exception, SystemException ya da ApplicationException'ı doğrudan fırlatmayın: çağıranlar geri kalan her şeyi de yakalamadan onları yakalayamaz. NullReferenceException, IndexOutOfRangeException ya da StackOverflowException'ı da kendiniz fırlatmayın; çalışma zamanı bunları gerçek hatalar için ayırır.
Throw ifadeleri
C# 7'den önce throw yalnızca bir deyimdi. C# 7'den beri üç yerde bir ifade olarak da görünebilir; bu da yaygın kontrolleri tek satıra çevirir:
Çıktı:
Ana <ana@example.com>
Null: name
ArgumentException: email
ArgumentNullException'ın ArgumentException'dan türediğine dikkat edin; bu yüzden başa konan bir catch (ArgumentException) null durumunu da yakalardı. İkisini birden ele aldığınızda catch cümlelerinin sırası aynı nedenle önemlidir.
ThrowIfNull ve benzerleri (.NET 6 ve sonrası)
Modern .NET, kontrolü ve fırlatmayı sizin için yazan, parametre adını otomatik yakalayan statik yardımcılar ekler:
public void Ship(Order order, int quantity, string address)
{
ArgumentNullException.ThrowIfNull(order); // .NET 6
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(quantity); // .NET 8
ArgumentException.ThrowIfNullOrWhiteSpace(address); // .NET 8
ObjectDisposedException.ThrowIf(disposed, this); // .NET 7
// ...
}
Elle yazılmış if ve throw ile aynı davranırlar ve koruma cümlelerini her biri tek satırda tutarlar. Eski hedeflerde daha önce gösterilen if biçimini yazın.
Özel bir istisna sınıfı yazmak
Çağıranların bu belirli başarısızlığı ayrıca yakalaması gerektiğinde ya da işleyicinin bir mesaj string'inin iyi taşıyamayacağı verilere ihtiyacı olduğunda kendi istisna tipinizi oluşturun.
Çıktı:
Cannot withdraw 25 from a balance of 15.
Short by 10
Gelenekler:
- Ad
Exceptionile biter. Exception'dan (ya daInvalidOperationExceptiongibi daha özel bir yerleşik tipin özel bir durumuysa ondan) türer.- Üç standart constructor'ı vardır: hiçbir şey, mesaj ve mesaj artı inner exception. Kendi constructor'larınızı bunların üzerine ekleyin.
- Ek veri, constructor'da ayarlanan salt okunur property'lere girer. Bir işleyici bundan sonra mesajı parse etmek yerine
e.Requested'a göre davranabilir.
Bir inner exception ile sarmalamak
Düşük seviyeli bir başarısızlığın daha yüksek seviyeli bir başarısızlık olarak ortaya çıkması gerektiğinde onu sarmalayın. Orijinal InnerException olarak tutulur, bu yüzden hiçbir bilgi kaybolmaz:
Çıktı:
Setting 'port' must be a number, got '80a'.
Caused by: FormatException
Çağıran artık anladığı yapılandırma terimleriyle muhatap olur ve e.ToString()'i log'a yazmak FormatException ve onun stack trace'i dahil tüm zinciri yazdırır. Yalnızca anlam kattığınızda sarmalayın; her istisnayı genel bir MyAppException içine sarmak işleyicilerin yalnızca InnerException'ı kazmasına yol açar.
İstisna fırlatmak ile bir sonuç döndürmek
İstisnalar, çağıranın normal işleyişte beklemediği başarısızlıklar içindir. Sık sık hiçbir şey bulamayan bir arama ya da sık sık geçersiz olan kullanıcı girdisi gibi olağan sonuçlar için .NET geleneği Try kalıbıdır: bool döndürün ve değeri bir out parametresiyle geri verin.
public bool TryWithdraw(decimal amount, out string error)
{
if (amount > Balance) { error = "Insufficient funds."; return false; }
Balance -= amount;
error = null;
return true;
}
Birçok tip ikisini de sunar: int.Parse istisna fırlatır, int.TryParse false döndürür; dict[key] istisna fırlatır, dict.TryGetValue false döndürür. Bir istisna fırlatmak bir değer döndürmekten çok daha pahalıdır, bu yüzden saniyede binlerce kez çalışan bir yolda durmamalıdır. out parametreleri için ref ve out sayfasına bakın.
İyi mesajlar yazmak
Bir istisna mesajı, bir log'a bakan bir geliştirici tarafından okunur. Neyin yanlış olduğunu ve güvenliyse sorunlu değeri belirtin: "Quantity must be between 1 and 99, got 0.", "Invalid input."'tan iyidir. Tam cümleler yazın ve parolalar ile token'lar gibi sırları mesajların dışında tutun, çünkü log dosyalarına düşerler.
Yaygın hatalar
Exception'ın kendisini fırlatmak. Çağıranlar onu seçici olarak yakalayamaz; özel bir tip kullanın.- Mesajı parametre adının yerine vermek.
new ArgumentNullException("name")parametre adını alır; mesaj ikinci sırada gelir. - Sabit kodlanmış parametre adları. Yeniden adlandırmalar onları doğru tutsun diye
nameof(param)kullanın. - Ek anlamı olmayan özel istisnalar. Yerleşik bir tip uyuyorsa onu kullanın.
- Sarmalarken orijinal hatayı kaybetmek. Onu her zaman inner exception olarak verin.
Sıkça Sorulan Sorular
C#'ta istisna nasıl fırlatılır?
Bir istisna nesnesi oluşturun ve fırlatın: throw new ArgumentException("Amount must be positive", nameof(amount));. Çalışma o satırda durur ve istisna çağrı yığınında en yakın eşleşen catch'e doğru yukarı çıkar. Sorunu tanımlayan en özel yerleşik tipi seçin ya da çağıranların bu durumu ayrıca ele alması gerektiğinde özel bir tip seçin.
C#'ta özel bir istisna nasıl oluşturulur?
Adı Exception ile biten, Exception'dan türeyen bir sınıf oluşturun ve ona standart constructor'ları verin: argümansız bir tane, bir mesaj alan bir tane ve bir mesaj ile bir inner exception alan bir tane; her biri eşleşen base(...) constructor'ını çağırır. Bir işleyicinin ihtiyaç duyduğu her veri için, örneğin bir sipariş ID'si ya da bir bakiye, salt okunur property'ler ekleyin.
Ne zaman ArgumentException, ne zaman InvalidOperationException fırlatılmalı?
Bir çağıran hatalı bir değer geçirdiğinde bir ArgumentException (ya da ArgumentNullException / ArgumentOutOfRangeException) fırlatın: çözüm metodu farklı çağırmaktır. Argümanlar sorunsuz ama nesne çağrı için yanlış durumdayken InvalidOperationException fırlatın; örneğin kapalı bir bağlantıdan okumak ya da dondurulmuş bir hesaptan para çekmek.
C#'ta throw ifadesi (throw expression) nedir?
C# 7'den beri throw üç yerde bir ifade olarak kullanılabilir: ??'den sonra, ?:'ın iki dalından biri olarak ve expression-bodied bir üyenin ya da lambda'nın gövdesi olarak. Örneğin _name = name ?? throw new ArgumentNullException(nameof(name)); tek satırda atar ya da fırlatır.
ArgumentNullException.ThrowIfNull ne yapar?
.NET 6'da eklenen statik bir yardımcıdır: ArgumentNullException.ThrowIfNull(customer); customer null olduğunda parametre adı otomatik doldurulmuş bir ArgumentNullException fırlatır, aksi halde hiçbir şey yapmaz. Sonraki sürümler ArgumentException.ThrowIfNullOrEmpty (.NET 7) ve ArgumentOutOfRangeException.ThrowIfNegative (.NET 8) gibi benzer yardımcılar ekledi.