Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
Uygun özel durum işleme, uygulama güvenilirliği için gereklidir. Uygulamanızın kilitlenmesini önlemek için beklenen özel durumları kasıtlı olarak işleyebilirsiniz. Ancak, kilitlenen bir uygulama, belirsiz davranışa sahip bir uygulamadan daha güvenilir ve teşhis edilebilir.
Bu makalede özel durumları işlemeye ve oluşturmaya yönelik en iyi yöntemler açıklanmaktadır.
Özel durumları işleme
Aşağıdaki en iyi yöntemler, özel durumları nasıl işlediğinizle ilgilidir:
- Hatalardan kurtulmak veya kaynakları serbest bırakmak için try/catch/finally bloklarını kullanın
- Özel durumları önlemek için yaygın durumları ele alın
- yakalama iptali ve asenkron özel durumlar
- Özel durumların önlenebilmesi için Tasarım sınıflarını
- Özel durumlar nedeniyle yöntemler tamamlanmadığında durumu geri yükle
- Özel durumları düzgün bir şekilde yakalayın ve yeniden fırlatın.
Hatalardan kurtulmak veya kaynakları serbest bırakmak için try/catch/finally bloklarını kullan.
Olası bir istisna oluşturabilecek kod ve uygulamanız bu istisnadan kurtulabileceğinde, kodu çevreleyen try/catch bloklarını kullanın.
catch bloklarda her zaman en çok türetilenden en az türetilene kadar özel durumları sıralar. (Tüm özel durumlar Exception sınıfından türetilir. catch yan tümcesi, daha fazla türetilmiş özel durumları, catch yan tümcesinin temel özel durum sınıfı için önce geldiği durumda işlemez.) Kodunuz bir özel durumdan kurtulamıyorsa, o özel durumu yakalamayın. Mümkünse kurtarmak için çağrı yığınında daha fazla yöntem etkinleştirin.
using ifadeleriyle veya finally bloklar ile ayrılan kaynakları temizleyin. İstisnalar atıldığında kaynakları otomatik olarak temizlemek için using ifadelerini tercih edin.
finallyuygulamayan kaynakları temizlemek için IDisposable blokları kullanın.
finally yan tümcesindeki kod, özel durumlar oluştuğunda bile neredeyse her zaman yürütülür.
Özel durumları önlemek için yaygın koşulları işleme
Olası fakat bir istisna tetikleyebilecek koşullar için, onları istisnadan kaçınacak şekilde işlemeyi düşünün. Örneğin, zaten kapalı olan bir bağlantıyı kapatmaya çalışırsanız, bir InvalidOperationExceptionalırsınız. Kapatmaya çalışmadan önce bağlantı durumunu denetlemek için bir if deyimi kullanarak bunu önleyebilirsiniz.
if (conn.State != ConnectionState.Closed)
{
conn.Close();
}
If conn.State <> ConnectionState.Closed Then
conn.Close()
End IF
Kapatmadan önce bağlantı durumunu denetlemezseniz, InvalidOperationException özel durumunu yakalayabilirsiniz.
try
{
conn.Close();
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.GetType().FullName);
Console.WriteLine(ex.Message);
}
Try
conn.Close()
Catch ex As InvalidOperationException
Console.WriteLine(ex.GetType().FullName)
Console.WriteLine(ex.Message)
End Try
Seçme yaklaşımı, olayın ne sıklıkta gerçekleşmesini beklediğinize bağlıdır.
Olay sık gerçekleşmiyorsa, yani olay gerçekten olağanüstüyse ve beklenmeyen bir dosya sonu gibi bir hata gösteriyorsa özel durum işlemeyi kullanın. Özel durum işleme kullandığınızda, normal koşullarda daha az kod yürütülür.
Olay düzenli olarak gerçekleşirse ve normal yürütmenin bir parçası olarak kabul edilebilirse koddaki hata koşullarını denetleyin. Yaygın hata koşullarını denetlediğinizde, özel durumlardan kaçındığınızdan daha az kod yürütülür.
Not
Ön denetimler çoğu zaman özel durumları ortadan kaldırır. Ancak denetim ile işlem arasında korunan koşulun değiştiği yarış durumları olabilir ve bu durumda yine de bir istisna ile karşılaşabilirsiniz.
Özel durumları önlemek için Try* yöntemlerini çağırma
Özel durumların performans maliyeti engelleyiciyse, bazı .NET kitaplık yöntemleri alternatif hata işleme biçimleri sağlar. Örneğin, ayrıştırılacak değer Int32.Parsetarafından temsil edilemeyecek kadar büyükse OverflowException bir Int32 oluşturur. Ancak Int32.TryParse bu istisnayı oluşturmaz. Bunun yerine bir Boole döndürür ve başarılı olduğunda ayrıştırılmış geçerli tamsayıyı içeren bir out parametresine sahiptir.
Dictionary<TKey,TValue>.TryGetValue, bir sözlükten değer almaya çalışırken benzer davranışlar gösterir.
İptal ve eşzamansız özel durumları yakalama
Asenkron bir yöntem çağırırken OperationCanceledException'den türetilen TaskCanceledExceptionyerine OperationCanceledException'ı yakalamak daha iyidir. İptal istenirse birçok zaman uyumsuz yöntem OperationCanceledException özel durumu oluşturur. Bu özel durumlar, bir iptal isteği gözlemlendikten sonra yürütmenin verimli bir şekilde durdurulmasını ve çağrı yığınının kaldırılabilmesini sağlar.
Zaman uyumsuz yöntemler, döndürdükleri görevde yürütme sırasında fırlatılan istisnaları depolar. Döndürülen görevde bir özel durum depolanırsa, görev beklenirken bu özel durum fırlatılır. ArgumentExceptiongibi kullanım özel durumları hâlâ eşzamanlı olarak fırlatılır. Daha fazla bilgi için bkz. zaman uyumsuz özel durumlar.
Özel durumların önlenebilmesi için sınıfları tasarlama
Bir sınıf, özel durum tetikleyebilecek bir çağrı yapmaktan kaçınmanızı sağlayan yöntemler veya özellikler sağlayabilir. Örneğin, FileStream sınıfı dosyanın sonuna ulaşılıp ulaşılmadığını belirlemeye yardımcı olan yöntemler sağlar. Dosyanın sonunu okursanız atılacak olan istisnadan kaçınmak için bu yöntemleri çağırabilirsiniz. Aşağıdaki örnekte, özel durum tetiklemeden dosyanın sonuna kadar okuma işlemi gösterilmektedir:
class FileRead
{
public static void ReadAll(FileStream fileToRead)
{
ArgumentNullException.ThrowIfNull(fileToRead);
int b;
// Set the stream position to the beginning of the file.
fileToRead.Seek(0, SeekOrigin.Begin);
// Read each byte to the end of the file.
for (int i = 0; i < fileToRead.Length; i++)
{
b = fileToRead.ReadByte();
Console.Write(b.ToString());
// Or do something else with the byte.
}
}
}
Class FileRead
Public Sub ReadAll(fileToRead As FileStream)
' This if statement is optional
' as it is very unlikely that
' the stream would ever be null.
If fileToRead Is Nothing Then
Throw New System.ArgumentNullException()
End If
Dim b As Integer
' Set the stream position to the beginning of the file.
fileToRead.Seek(0, SeekOrigin.Begin)
' Read each byte to the end of the file.
For i As Integer = 0 To fileToRead.Length - 1
b = fileToRead.ReadByte()
Console.Write(b.ToString())
' Or do something else with the byte.
Next i
End Sub
End Class
Özel durumlardan kaçınmanın bir diğer yolu da, özel durum oluşturma yerine en yaygın hata durumlarında null (veya varsayılan) döndürmektir. Yaygın bir hata durumu, normal bir denetim akışı olarak kabul edilebilir. Bu durumlarda null (veya varsayılan) döndürerek, uygulama üzerindeki performans etkisini en aza indirirsiniz.
Değer türleri için uygulamanızın hata göstergesi olarak Nullable<T> mi yoksa default mi kullanacağınızı düşünün.
Nullable<Guid>kullanarak defaultnullyerine Guid.Empty olur. Bazen Nullable<T> eklemek, bir değer mevcut olduğunda veya olmadığında bunu daha net hale getirir. Bazen Nullable<T> eklemek, gereksiz ek durumlar oluşturabilir ve sadece potansiyel hata kaynakları yaratmaya hizmet edebilir.
Yöntemler, özel durumlar nedeniyle tamamlanmadığında durumu geri yükleyin.
Çağıranlar, bir yöntemden istisna fırlatıldığında herhangi bir yan etkinin olmadığını varsayabilmelidir. Örneğin, bir hesaptan para çekerek ve başka bir hesaba para yatırarak para aktaran kodunuz varsa ve depozito yürütülürken bir özel durum oluşursa, çekme işleminin geçerli kalmasını istemezsiniz.
public void TransferFunds(Account from, Account to, decimal amount)
{
from.Withdrawal(amount);
// If the deposit fails, the withdrawal shouldn't remain in effect.
to.Deposit(amount);
}
Public Sub TransferFunds(from As Account, [to] As Account, amount As Decimal)
from.Withdrawal(amount)
' If the deposit fails, the withdrawal shouldn't remain in effect.
[to].Deposit(amount)
End Sub
Yukarıdaki yöntem doğrudan herhangi bir özel durum oluşturmaz. Ancak, para yatırma işlemi başarısız olursa para çekme işleminin tersine çevrilmesi için yöntemini yazmanız gerekir.
Bu durumu ele almanın bir yolu, para yatırma işlemi sırasında ortaya çıkan hataları yakalamak ve para çekme işlemini geri döndürmektir.
private static void TransferFunds(Account from, Account to, decimal amount)
{
string withdrawalTrxID = from.Withdrawal(amount);
try
{
to.Deposit(amount);
}
catch
{
from.RollbackTransaction(withdrawalTrxID);
throw;
}
}
Private Shared Sub TransferFunds(from As Account, [to] As Account, amount As Decimal)
Dim withdrawalTrxID As String = from.Withdrawal(amount)
Try
[to].Deposit(amount)
Catch
from.RollbackTransaction(withdrawalTrxID)
Throw
End Try
End Sub
Bu örnek, özgün özel durumu yeniden oluşturmak için throw kullanımını gösterir ve arayanların InnerException özelliğini incelemek zorunda kalmadan sorunun gerçek nedenini görmelerini kolaylaştırır. Alternatif olarak yeni bir özel durum oluşturup özgün özel durumu iç özel durum olarak dahil edin.
catch (Exception ex)
{
from.RollbackTransaction(withdrawalTrxID);
throw new TransferFundsException("Withdrawal failed.", innerException: ex)
{
From = from,
To = to,
Amount = amount
};
}
Catch ex As Exception
from.RollbackTransaction(withdrawalTrxID)
Throw New TransferFundsException("Withdrawal failed.", innerException:=ex) With
{
.From = from,
.[To] = [to],
.Amount = amount
}
End Try
Özel durumları düzgün bir şekilde yakalama ve yeniden düzeltme
Bir özel durum fırlatıldığında, taşıdığı bilgilerin bir bölümü yığın izidir. Yığın izlemesi, özel durumu oluşturan yöntemiyle başlayan ve özel durumu yakalayan yöntemle biten yöntem çağrısı hiyerarşisinin listesidir.
throw deyiminde özel durumu belirterek bir özel durumu yeniden oluşturursanız( örneğin, throw e) yığın izlemesi geçerli yöntemde yeniden başlatılır ve özel durumu oluşturan özgün yöntem ile geçerli yöntem arasındaki yöntem çağrılarının listesi kaybolur. Özgün yığın izleme bilgilerini özel durumla birlikte tutmak için, özel durumu nereden yeniden oluşturduğunuza bağlı olarak iki seçenek vardır:
- Özel durum örneğini yakalayan işleyiciden (
catchblok) özel durumu yeniden fırlatırsanız, yakalanan özel durumu belirtmedenthrowdeyimini kullanın. CA2200 kod çözümleme kuralı, kodunuzda yanlışlıkla yığın izleme bilgilerini kaybedebileceğiniz yerleri bulmanıza yardımcı olur. - Özel durumu işleyici (
catchblok) dışında bir yerden yeniden fırlatacaksanız, işleyicide özel durumu yakalamak için ExceptionDispatchInfo.Capture(Exception)'i ve yeniden fırlatmak istediğinizde ExceptionDispatchInfo.Throw()'yi kullanın. Yakalanan özel durumu incelemek için ExceptionDispatchInfo.SourceException özelliğini kullanabilirsiniz.
Aşağıdaki örnek, ExceptionDispatchInfo sınıfının nasıl kullanılabileceğini ve çıkışın nasıl görünebileceğini gösterir.
ExceptionDispatchInfo? edi = null;
try
{
var txt = File.ReadAllText(@"C:\temp\file.txt");
}
catch (FileNotFoundException e)
{
edi = ExceptionDispatchInfo.Capture(e);
}
// ...
Console.WriteLine("I was here.");
if (edi is not null)
edi.Throw();
Örnek koddaki dosya yoksa aşağıdaki çıkış oluşturulur:
I was here.
Unhandled exception. System.IO.FileNotFoundException: Could not find file 'C:\temp\file.txt'.
File name: 'C:\temp\file.txt'
at Microsoft.Win32.SafeHandles.SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.Strategies.FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
at System.IO.StreamReader.ValidateArgsAndOpenPath(String path, Encoding encoding, Int32 bufferSize)
at System.IO.File.ReadAllText(String path, Encoding encoding)
at Example.ProcessFile.Main() in C:\repos\ConsoleApp1\Program.cs:line 12
--- End of stack trace from previous location ---
at Example.ProcessFile.Main() in C:\repos\ConsoleApp1\Program.cs:line 24
Özel durumlar oluşturma
Aşağıdaki en iyi yöntemler özel durumları nasıl oluşturabileceğinizle ilgilidir:
- Önceden tanımlanmış özel durum türlerini kullanma
- özel durum oluşturucu yöntemlerini kullanma
- Yerelleştirilmiş dize iletisi ekleme
- Uygun dil bilgisi kullanma
- Throw deyimlerini iyi yerleştirin
- Finally yan tümcelerinde istisnalar oluşturmayın
- Beklenmeyen yerlerden özel durumlar
- Bağımsız değişken doğrulama hatalarını senkronize olarak atın
Önceden tanımlanmış özel durum türlerini kullanma
Yeni bir özel durum sınıfını yalnızca önceden tanımlanmış bir sınıf geçerli olmadığında tanıtın. Örneğin:
- Nesnenin geçerli durumu göz önüne alındığında bir özellik kümesi veya yöntem çağrısı uygun değilse, InvalidOperationException özel durumu oluşturun.
- Geçersiz parametreler geçersizse, bir ArgumentException özel durumu veya ArgumentExceptionsınıfından türetilmiş önceden tanımlanmış sınıflardan birini atın.
Not
Mümkün olduğunda önceden tanımlanmış özel durum türlerini kullanmak en iyisi olsa da, , AccessViolationException, IndexOutOfRangeException ve NullReferenceExceptiongibi bazı StackOverflowException özel durum türlerini tetiklememelisiniz. Daha fazla bilgi için bkz. CA2201: Ayrılmış özel durum türlerini tetikleme.
Özel durum oluşturucu yöntemlerini kullanma
Bir sınıfın, uygulamasında farklı yerlerden aynı özel durumu oluşturması yaygındır. Aşırı kodu önlemek için, özel durumu oluşturan ve döndüren bir yardımcı yöntem oluşturun. Örneğin:
class FileReader
{
private readonly string _fileName;
public FileReader(string path)
{
_fileName = path;
}
public byte[] Read(int bytes)
{
byte[] results = FileUtils.ReadFromFile(_fileName, bytes) ?? throw NewFileIOException();
return results;
}
static FileReaderException NewFileIOException()
{
string description = "My NewFileIOException Description";
return new FileReaderException(description);
}
}
Class FileReader
Private fileName As String
Public Sub New(path As String)
fileName = path
End Sub
Public Function Read(bytes As Integer) As Byte()
Dim results() As Byte = FileUtils.ReadFromFile(fileName, bytes)
If results Is Nothing
Throw NewFileIOException()
End If
Return results
End Function
Function NewFileIOException() As FileReaderException
Dim description As String = "My NewFileIOException Description"
Return New FileReaderException(description)
End Function
End Class
Bazı anahtar .NET özel durum türleri, özel durumu ayıran ve fırlatan statik throw yardımcı yöntemlerine sahiptir. İlgili özel durum türünü oluşturup fırlatmak yerine bu yöntemleri çağırmalısınız.
- ArgumentNullException.ThrowIfNull
- ArgumentException.ThrowIfNullOrEmpty(String, String)
- ArgumentException.ThrowIfNullOrWhiteSpace(String, String)
- ArgumentOutOfRangeException.ThrowIfZero<T>(T, String)
- ArgumentOutOfRangeException.ThrowIfNegative<T>(T, String)
- ArgumentOutOfRangeException.ThrowIfEqual<T>(T, T, String)
- ArgumentOutOfRangeException.ThrowIfLessThan<T>(T, T, String)
- ArgumentOutOfRangeException.ThrowIfNotEqual<T>(T, T, String)
- ArgumentOutOfRangeException.ThrowIfNegativeOrZero<T>(T, String)
- ArgumentOutOfRangeException.ThrowIfGreaterThan<T>(T, T, String)
- ArgumentOutOfRangeException.ThrowIfLessThanOrEqual<T>(T, T, String)
- ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<T>(T, T, String)
- ObjectDisposedException.ThrowIf
Bahşiş
Aşağıdaki kod çözümleme kuralları, kodunuzda bu statik throw yardımcılarından yararlanabileceğiniz yerler bulmanıza yardımcı olabilir: CA1510, CA1511, CA1512ve CA1513.
Zaman uyumsuz bir yöntem uyguluyorsanız, iptalin istenip istenmediğini denetleyip ardından CancellationToken.ThrowIfCancellationRequested()oluşturup atmaktansa, OperationCanceledException çağırın. Daha fazla bilgi için bkz. CA2250.
Yerelleştirilmiş dize iletisi ekleme
Kullanıcının gördüğü hata iletisi, özel durum sınıfının adından değil, oluşan özel durumun Exception.Message özelliğinden türetilir. Genellikle, ileti dizesini Exception.MessageÖzel Durum oluşturucusunun message bağımsız değişkenine geçirerek özelliğine bir değer atarsınız.
Yerelleştirilmiş uygulamalar için, uygulamanızın oluşturabileceği her özel durum için yerelleştirilmiş bir ileti dizesi sağlamanız gerekir. Yerelleştirilmiş hata iletileri sağlamak için kaynak dosyalarını kullanırsınız. Uygulamaları yerelleştirme ve yerelleştirilmiş dizeleri alma hakkında bilgi için aşağıdaki makalelere bakın:
- Nasıl yapılır: Yerelleştirilmiş özel durum iletileriyle kullanıcı tanımlı özel durumlar oluşturma
- .NET uygulamalarında kaynakları
- System.Resources.ResourceManager
Uygun dil bilgisini kullanma
Net cümleler yazın ve bitiş noktalama işaretlerini ekleyin. Exception.Message özelliğine atanan dizedeki her tümce bir süre içinde bitmelidir. Örneğin, "Günlük tablosu taşmış." doğru dil bilgisi ve noktalama işaretlerini kullanır.
Throw deyimlerini doğru şekilde yerleştir
Throw deyimlerini yığın izlemesinin yararlı olduğu yere yerleştirin. Yığın izlemesi, özel durumun oluştuğu deyimde başlar ve özel durumu yakalayan catch deyiminde biter.
finally bloklarında istisna oluşturmayın
finally yan tümcelerinde istisna oluşturmayın. Daha fazla bilgi için bkz. CA2219 kod çözümleme kuralı.
Beklenmeyen yerlerden özel durum oluşturmayın
Equals, GetHashCodeve ToString yöntemleri, statik oluşturucular ve eşitlik işleçleri gibi bazı yöntemler özel durumlar oluşturmamalıdır. Daha fazla bilgi için bkz. CA1065 kod çözümleme kuralı.
Bağımsız değişken doğrulama özel durumlarını eşzamanlı olarak fırlatın.
Görev döndüren yöntemlerde, yöntemin zaman uyumsuz bölümünü girmeden önce bağımsız değişkenleri doğrulamanız ve ArgumentException ve ArgumentNullExceptiongibi ilgili özel durumları oluşturmanız gerekir. Yöntemin zaman uyumsuz bölümünde oluşan özel durumlar, döndürülen görevde depolanır ve örneğin görev beklenene kadar ortaya çıkmaz. Daha fazla bilgi için bkz. görev döndüren yöntemlerde istisnalar.
Özel istisna türleri
Aşağıdaki en iyi yöntemler özel özel durum türleriyle ilgilidir:
-
Özel durum sınıfı adlarını
Exceptionile sonlandır - üç tane oluşturucu ekleyin
- Gerektiğinde daha fazla özellik sağlayın
özel durum sınıfı adlarını Exception ile sonlandırma
Özel bir özel durum gerektiğinde, bunu uygun şekilde adlandırın ve Exception sınıfından türetin. Örneğin:
public class MyFileNotFoundException : Exception
{
}
Public Class MyFileNotFoundException
Inherits Exception
End Class
Üç oluşturucu dahil et
Kendi özel durum sınıflarınızı oluştururken en az üç ortak oluşturucu kullanın: parametresiz oluşturucu, dize iletisi alan bir oluşturucu ve dize iletisi ve iç özel durum alan bir oluşturucu.
- Exception(), varsayılan değerleri kullanır.
- dize iletisini kabul eden Exception(String).
- Exception(String, Exception), bir string mesajı ve bir iç istisna kabul eder.
Örnek için bkz. Nasıl yapılır:kullanıcı tanımlı özel durumlar oluşturma.
Gerektiğinde daha fazla özellik sağlayın
Yalnızca ek bilgilerin yararlı olduğu programlı bir senaryo olduğunda özel durum (özel ileti dizesine ek olarak) için daha fazla özellik sağlayın. Örneğin, FileNotFoundExceptionFileName özelliğini sağlar.