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.
Özel durum işleme deyimleri -
özel durumlarla çalışmak için ve throw deyimlerini kullanırsınıztry. Özel durum atmak için deyimini throw kullanın. Bir kod bloğunun try yürütülmesi sırasında oluşabilecek özel durumları yakalamak ve işlemek için deyimini kullanın.
Deyimi throw
deyimi throw bir özel durum oluşturur:
if (shapeAmount <= 0)
{
throw new ArgumentOutOfRangeException(nameof(shapeAmount), "Amount of shapes must be positive.");
}
Deyiminde throw e; , ifadenin e sonucu örtük olarak olarak olarak System.Exceptiondönüştürülebilir olmalıdır.
Örneğin, ArgumentOutOfRangeExceptionInvalidOperationExceptionveya yerleşik özel durum sınıflarını kullanabilirsiniz. .NET ayrıca belirli koşullarda özel durumlar atmak için aşağıdaki yardımcı yöntemleri de sağlar: ArgumentNullException.ThrowIfNull ve ArgumentException.ThrowIfNullOrEmpty. 'den System.Exceptiontüretilen kendi özel durum sınıflarınızı da tanımlayabilirsiniz. Daha fazla bilgi için bkz . Özel durumlar oluşturma ve oluşturma.
Bir catch bloğun içinde, bloğu tarafından throw; işlenen özel durumu yeniden oluşturmak için deyimini catch kullanabilirsiniz:
try
{
ProcessShapes(shapeAmount);
}
catch (Exception e)
{
LogError(e, "Shape processing failed.");
throw;
}
Not
throw; özelliğinde depolanan özel durumun özgün yığın izlemesini Exception.StackTrace korur. Bunun tersi, throw e; özelliğini StackTracegüncelleştirire.
Özel durum oluşturulduğunda, ortak dil çalışma zamanı (CLR) bu özel durumu işleyebilen bloğucatch. Şu anda yürütülen yöntem böyle bir catch blok içermiyorsa, CLR geçerli yöntemi çağıran yönteme bakar ve çağrı yığınını yukarı doğru kullanır. Blok catch bulunmazsa, CLR yürütülen iş parçacığını sonlandırır. Daha fazla bilgi için C# dil belirtiminin Özel durumlar nasıl işlenir bölümüne bakın.
İfade throw
İfade olarak da kullanabilirsiniz throw . Bu, aşağıdakileri içeren birkaç durumda kullanışlı olabilir:
koşullu işleç. Aşağıdaki örnek, geçirilen dizi
throwboş olduğunda oluşturmak için bir ArgumentExceptionargsifade kullanır:string first = args.Length >= 1 ? args[0] : throw new ArgumentException("Please supply at least one argument.");null-coalescing işleci. Aşağıdaki örnek, bir
throwözelliğe atanacak dize olduğunda ArgumentNullExceptionoluşturmak için bir ifadenullkullanır:public string Name { get => name; set => name = value ?? throw new ArgumentNullException(paramName: nameof(value), message: "Name cannot be null"); }ifade gövdeli lambda veya yöntem. Aşağıdaki örnek, bir
throwdeğere InvalidCastException dönüştürmenin desteklenmediğini belirtmek üzere oluşturmak için bir DateTime ifade kullanır:DateTime ToDateTime(IFormatProvider provider) => throw new InvalidCastException("Conversion to a DateTime is not supported.");
Deyimi try
deyimini try aşağıdaki formlardan herhangi birinde kullanabilirsiniz: try-catch - bir try bloğun içindeki kodun yürütülmesi sırasında oluşabilecek özel durumları işlemek için, try-finally denetim bloktan ayrıldığında try yürütülen kodu belirtmek için ve try-catch-finally - önceki iki formun bir bileşimi olarak.
Deyimi try-catch
Kod bloğunun try-catch yürütülmesi sırasında oluşabilecek özel durumları işlemek için deyimini kullanın. Kodu bir bloğun içinde özel durumun oluşabileceği yere try yerleştirin.
kullanın:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Birkaç catch yan tümcesi sağlayabilirsiniz:
try
{
var result = await ProcessAsync(-3, 4, cancellationToken);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
catch (OperationCanceledException)
{
Console.WriteLine("Processing is cancelled.");
}
Bir özel durum oluştuğunda, catch yan tümceleri yukarıdan aşağıya doğru belirtilen sırada incelenir. En fazla, oluşan özel durumlar için yalnızca bir catch blok yürütülür. Yukarıdaki örnekte de gösterildiği gibi, bir özel durum değişkeninin bildirimini atlayabilir ve catch yan tümcesinde yalnızca özel durum türünü belirtebilirsiniz. Belirtilen özel durum türü olmayan catch yan tümcesi herhangi bir özel durumla eşleşir ve varsa son catch yan tümcesi olmalıdır.
Yakalanan bir özel durumu yeniden oluşturmak istiyorsanız, aşağıdaki örnekte gösterildiği gibi deyimini throwkullanın:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e)
{
LogError(e, "Processing failed.");
throw;
}
Not
throw; özelliğinde depolanan özel durumun özgün yığın izlemesini Exception.StackTrace korur. Bunun tersi, throw e; özelliğini StackTracegüncelleştirire.
Özel when durum filtresi
Özel durum türüyle birlikte, bir özel durumu daha ayrıntılı olarak inceleyen ve ilgili catch bloğun bu özel durumu işleyip işlemeyeceğine karar veren bir özel durum filtresi de belirtebilirsiniz. Özel durum filtresi, aşağıdaki örnekte gösterildiği gibi anahtar sözcüğü izleyen when bir Boole ifadesidir:
try
{
var result = Process(-3, 4);
Console.WriteLine($"Processing succeeded: {result}");
}
catch (Exception e) when (e is ArgumentException || e is DivideByZeroException)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
Yukarıdaki örnek, belirtilen iki türün özel durumlarını işlemek için tek catch bir blok sağlamak için bir özel durum filtresi kullanır.
Özel durum filtreleriyle ayırt edilirlerse aynı özel durum türü için birkaç catch yan tümce sağlayabilirsiniz. Bu yan tümcelerden birinde özel durum filtresi olmayabilir. Böyle bir yan tümce varsa, bu özel durum türünü belirten yan tümcelerin sonuncusu olmalıdır.
Yan catch tümcesinde özel durum filtresi varsa, bundan sonra görüntülenen bir yan tümcenin özel durum türüyle aynı veya daha az türetilmiş özel durum türünü catch belirtebilir. Örneğin, bir özel durum filtresi varsa, yan catch (Exception e) tümcesinin son yan tümcesi olması gerekmez.
Özel durum filtreleri ile geleneksel özel durum işleme karşılaştırması
Özel durum filtreleri, geleneksel özel durum işleme yaklaşımlarına göre önemli avantajlar sağlar. Önemli fark, özel durum işleme mantığının değerlendirildiğinde olmasıdır:
-
Özel durum filtreleri (
when): Filtre ifadesi, yığın kaldırılmadan önce değerlendirilir. Bu, özgün çağrı yığınının ve tüm yerel değişkenlerin filtre değerlendirmesi sırasında olduğu gibi kaldığı anlamına gelir. -
Geleneksel
catchbloklar: Yığın kaldırıldıktan sonra catch bloğu yürütülür ve büyük olasılıkla değerli hata ayıklama bilgileri kaybedilir.
Farkı gösteren bir karşılaştırma aşağıdadır:
public static void DemonstrateStackUnwindingDifference()
{
var localVariable = "Important debugging info";
try
{
ProcessWithExceptionFilter(localVariable);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("filter"))
{
// Exception filter: Stack not unwound yet.
// localVariable is still accessible in debugger.
// Call stack shows original throwing location.
Console.WriteLine($"Caught with filter: {ex.Message}");
Console.WriteLine($"Local variable accessible: {localVariable}");
}
try
{
ProcessWithTraditionalCatch(localVariable);
}
catch (InvalidOperationException ex)
{
// Traditional catch: Stack already unwound.
// Some debugging information may be lost.
if (ex.Message.Contains("traditional"))
{
Console.WriteLine($"Caught with if: {ex.Message}");
Console.WriteLine($"Local variable accessible: {localVariable}");
}
else
{
throw; // Re-throws and further modifies stack trace.
}
}
}
private static void ProcessWithExceptionFilter(string context)
{
throw new InvalidOperationException($"Exception for filter demo: {context}");
}
private static void ProcessWithTraditionalCatch(string context)
{
throw new InvalidOperationException($"Exception for traditional demo: {context}");
}
Özel durum filtrelerinin avantajları
- Daha iyi hata ayıklama deneyimi: Bir filtre eşleşmeden yığın kaldırılmadığından, hata ayıklayıcılar özgün hata noktasını tüm yerel değişkenler olduğu gibi gösterebilir.
- Performans avantajları: Hiçbir filtre eşleşmezse, yığın geri yükleme ve geri yükleme ek yükü olmadan özel durum yayılmaya devam eder.
- Daha temiz kod: Birden çok filtre, iç içe if-else deyimlerine gerek kalmadan aynı özel durum türünün farklı koşullarını işleyebilir.
- Günlüğe kaydetme ve tanılama: Özel durumun işlenip işlenmeyeceğine karar vermeden önce özel durum ayrıntılarını inceleyebilir ve günlüğe kaydedebilirsiniz:
public static void DemonstrateDebuggingAdvantage()
{
var contextData = new Dictionary<string, object>
{
["RequestId"] = Guid.NewGuid(),
["UserId"] = "user123",
["Timestamp"] = DateTime.Now
};
try
{
// Simulate a deep call stack.
Level1Method(contextData);
}
catch (Exception ex) when (LogAndFilter(ex, contextData))
{
// This catch block may never execute if LogAndFilter returns false.
// But LogAndFilter can examine the exception while the stack is intact.
Console.WriteLine("Exception handled after logging");
}
}
private static void Level1Method(Dictionary<string, object> context)
{
Level2Method(context);
}
private static void Level2Method(Dictionary<string, object> context)
{
Level3Method(context);
}
private static void Level3Method(Dictionary<string, object> context)
{
throw new InvalidOperationException("Error in deep call stack");
}
private static bool LogAndFilter(Exception ex, Dictionary<string, object> context)
{
// This method runs before stack unwinding.
// Full call stack and local variables are still available.
Console.WriteLine($"Exception occurred: {ex.Message}");
Console.WriteLine($"Request ID: {context["RequestId"]}");
Console.WriteLine($"Full stack trace preserved: {ex.StackTrace}");
// Return true to handle the exception, false to continue search.
return ex.Message.Contains("deep call stack");
}
Özel durum filtreleri ne zaman kullanılır?
Aşağıdaki durumlarda özel durum filtrelerini kullanın:
- Özel durumları belirli koşullara veya özelliklere göre işleyin.
- Hata ayıklama için özgün çağrı yığınını koruyun.
- İşlenip işlenmeyeceğine karar vermeden önce özel durumları günlüğe kaydetme veya inceleme.
- Bağlama göre aynı özel durum türünü farklı şekilde işleyebilir.
public static void HandleFileOperations(string filePath)
{
try
{
// Simulate file operation that might fail.
ProcessFile(filePath);
}
catch (IOException ex) when (ex.Message.Contains("access denied"))
{
Console.WriteLine("File access denied. Check permissions.");
}
catch (IOException ex) when (ex.Message.Contains("not found"))
{
Console.WriteLine("File not found. Verify the path.");
}
catch (IOException ex) when (IsNetworkPath(filePath))
{
Console.WriteLine($"Network file operation failed: {ex.Message}");
}
catch (IOException)
{
Console.WriteLine("Other I/O error occurred.");
}
}
private static void ProcessFile(string filePath)
{
// Simulate different types of file exceptions.
if (filePath.Contains("denied"))
throw new IOException("File access denied");
if (filePath.Contains("missing"))
throw new IOException("File not found");
if (IsNetworkPath(filePath))
throw new IOException("Network timeout occurred");
}
private static bool IsNetworkPath(string path)
{
return path.StartsWith(@"\\") || path.StartsWith("http");
}
Yığın izleme koruması
Özel durum filtreleri özgün ex.StackTrace özelliği korur. Bir catch yan tümcesi özel durumu işleyemez ve yeniden oluşturursa, özgün yığın bilgileri kaybolur. Filtre when yığını geri sarmaz, bu nedenle bir when filtre ise falseözgün yığın izlemesi değiştirilmez.
Özel durum filtresi yaklaşımı, hata ayıklama bilgilerinin korunmasının sorunları tanılamak için çok önemli olduğu uygulamalarda değerlidir.
Zaman uyumsuz ve yineleyici yöntemlerindeki özel durumlar
Zaman uyumsuz bir işlevde özel durum oluşursa, aşağıdaki örnekte gösterildiği gibi işlevin sonucunu beklediğinizde işlevi çağırana yayılır:
public static async Task Run()
{
try
{
Task<int> processing = ProcessAsync(-1);
Console.WriteLine("Launched processing.");
int result = await processing;
Console.WriteLine($"Result: {result}.");
}
catch (ArgumentException e)
{
Console.WriteLine($"Processing failed: {e.Message}");
}
// Output:
// Launched processing.
// Processing failed: Input must be non-negative. (Parameter 'input')
}
private static async Task<int> ProcessAsync(int input)
{
if (input < 0)
{
throw new ArgumentOutOfRangeException(nameof(input), "Input must be non-negative.");
}
await Task.Delay(500);
return input;
}
Yineleyici yönteminde bir özel durum oluşursa, yalnızca yineleyici sonraki öğeye ilerlediğinde çağırana yayılır.
Deyimi try-finally
Deyiminde try-finallyfinally , denetim bloğu terk try ettiğinde blok yürütülür. Denetim, bunun sonucunda blokta try kalabilir
- normal yürütme,
- atlama deyiminin yürütülmesi (,
return,break,continueveya ) veyagoto - bir özel durumun bloğun dışına yayılması
try.
Aşağıdaki örnek, denetimin finally yöntemden ayrılmadan önce bir nesnenin durumunu sıfırlamak için bloğunu kullanır:
public async Task HandleRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
finally
{
Busy = false;
}
}
Blokta finally kullanılan ayrılmış kaynakları temizlemek için bloğunu try da kullanabilirsiniz.
Not
Bir kaynağın türü veya arabirimini uyguladığında IDisposable deyimini IAsyncDisposablegöz önünde bulundurun.using deyimi, using denetim deyiminden ayrıldığında using alınan kaynakların atılmasını sağlar. Derleyici bir using deyimini deyimine try-finally dönüştürür.
Bloğun finally yürütülmesi, işletim sisteminin bir özel durum geri alma işlemini tetikleyip tetiklemediğine bağlıdır. Blokların yürütülmemesi yalnızca finally programın hemen sonlandırılmasını içerir. Örneğin, böyle bir sonlandırma, çağrı veya bir Environment.FailFast veya OverflowException özel durum nedeniyle InvalidProgramException oluşabilir. çoğu işletim sistemi, işlemi durdurma ve kaldırma işleminin bir parçası olarak makul bir kaynak temizleme işlemi gerçekleştirir.
Deyimi try-catch-finally
Hem bloğun yürütülmesi try-catch-finally sırasında oluşabilecek özel durumları işlemek hem de denetim deyiminden ayrıldığında try yürütülmesi gereken kodu belirtmek için bir try deyim kullanırsınız:
public async Task ProcessRequest(int itemId, CancellationToken ct)
{
Busy = true;
try
{
await ProcessAsync(itemId, ct);
}
catch (Exception e) when (e is not OperationCanceledException)
{
LogError(e, $"Failed to process request for item ID {itemId}.");
throw;
}
finally
{
Busy = false;
}
}
Bir özel durum bir catch blok tarafından işlendiğinde, bloğun finally yürütülmesinden sonra (bloğun catch yürütülmesi catch sırasında başka bir özel durum gerçekleşse bile) blok yürütülür. ve blokları hakkında catch bilgi için sırasıyla Deyimifinally.try-catch
C# dili belirtimi
Daha fazla bilgi için C# dil belirtiminin aşağıdaki bölümlerine bakın: