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.
Kullanıcı kodu tarafından bir görev içinde atılan ele alınmamış istisnalar, bu konunun ilerleyen bölümlerinde açıklanan bazı senaryolar dışında, çağıran iş parçacığına geri iletilir. Statik veya örnek Task.Wait yöntemlerinden birini kullandığınızda, özel durumlar yayılır; bunları, çağrıyı bir try
/catch
deyimi içine alarak işlersiniz. Görev, bağlı alt görevlerin üst öğesiyse veya birden fazla görev bekliyorsanız, birden fazla istisna fırlatılabilir.
Tüm özel durumları çağıran iş parçacığına geri iletmek için Görev altyapısı bunları bir AggregateException örneği içine sarmalar. AggregateException özel durum, atılan tüm özgün özel durumları incelemek ve her birini ayrı ayrı işlemek (veya işlememek) için numaralandırılabilir bir InnerExceptions özelliğe sahiptir. Ayrıca AggregateException.Handle yöntemini kullanarak özgün özel durumları da işleyebilirsiniz.
Yalnızca bir özel durum oluşturulduğunda bile, aşağıdaki örnekte gösterildiği gibi bir AggregateException özel durum içinde sarmalanır.
public static partial class Program
{
public static void HandleThree()
{
var task = Task.Run(
() => throw new CustomException("This exception is expected!"));
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
// Handle the custom exception.
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
// Rethrow any other exception.
else
{
throw ex;
}
}
}
}
}
// The example displays the following output:
// This exception is expected!
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.InnerExceptions
' Handle the custom exception.
If TypeOf ex Is CustomException Then
Console.WriteLine(ex.Message)
' Rethrow any other exception.
Else
Throw ex
End If
Next
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' This exception is expected!
Siz sadece AggregateException öğesini yakalayarak ve iç özel durumları gözlemlemeyerek kontrol edilmeyen bir özel durumu önleyebilirsiniz. Ancak, paralel olmayan senaryolarda temel Exception türü yakalamaya benzer olduğundan bunu yapmamanızı öneririz. Belirli eylemler gerçekleştirmeden bir istisnayı yakalamak, programınızı belirsiz bir durumda bırakabilir.
Görevin tamamlanmasını beklemek için Task.Wait yöntemini çağırmak istemiyorsanız, aşağıdaki örnekte gösterildiği gibi özel durumu görevin AggregateExceptionException özelliğinden de alabilirsiniz. Daha fazla bilgi için bu konudaki Task.Exception özelliğini kullanarak özel durumları gözlemleme bölümüne bakın.
public static partial class Program
{
public static void HandleFour()
{
var task = Task.Run(
() => throw new CustomException("This exception is expected!"));
while (!task.IsCompleted) { }
if (task.Status == TaskStatus.Faulted)
{
foreach (var ex in task.Exception?.InnerExceptions ?? new(Array.Empty<Exception>()))
{
// Handle the custom exception.
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
// Rethrow any other exception.
else
{
throw ex;
}
}
}
}
}
// The example displays the following output:
// This exception is expected!
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))
While Not task1.IsCompleted
End While
If task1.Status = TaskStatus.Faulted Then
For Each ex In task1.Exception.InnerExceptions
' Handle the custom exception.
If TypeOf ex Is CustomException Then
Console.WriteLine(ex.Message)
' Rethrow any other exception.
Else
Throw ex
End If
Next
End If
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' This exception is expected!
Dikkat
Yukarıdaki örnek kod, görevin ne zaman tamamlandığını belirlemek için görevin while
özelliğini yoklayan bir Task.IsCompleted döngü içerir. Bu, çok verimsiz olduğundan üretim kodunda asla yapılmamalıdır.
Bir görevin tamamlanmasını beklemez veya Exception özelliğine erişmezseniz, görev çöp toplama yapıldığında özel durum .NET özel durum ilkesine göre yükseltilir.
Özel durumların birleştirilmiş iş parçacığına geri dönmesine izin verildiğinde, özel durum yükseltildikten sonra bir görevin bazı öğeleri işlemeye devam etmesi mümkündür.
Uyarı
"Yalnızca Benim Kodum" etkinleştirildiğinde, bazı durumlarda Visual Studio özel durumu oluşturan satırda kırılır ve "özel durum kullanıcı kodu tarafından işlenmez" hata iletisini görüntüler. Bu hata zararsızdır. Devam etmek için F5 tuşuna basabilir ve bu örneklerde gösterildiği gibi özel durum işleme davranışını görebilirsiniz. Visual Studio'nun ilk hatada hata vermesini önlemek için Araçlar, Seçenekler, Hata Ayıklama, Genel altındaki Yalnızca Kodumu Etkinleştir onay kutusunun işaretini kaldırması gerekir.
Eklenen alt görevler ve iç içe geçmiş AggregateExceptions
Bir görevin, özel durum oluşturan ekli bir alt görevi varsa, bu özel durum üst göreve yayılmadan önce bir AggregateException içinde sarılır; üst görev de bu özel durumu, çağıran iş parçacığına geri yayılmadan önce kendi AggregateException içinde sarar. Böyle durumlarda, InnerExceptions, AggregateException veya Task.Wait yönteminde yakalanan WaitAny özel durumunun WaitAll özelliği, hataya neden olan orijinal özel durumlar yerine, bir veya daha fazla AggregateException örneği içerir. İç içe AggregateException özel durumları yinelemek zorunda kalmamak için, tüm iç içe Flatten özel durumları kaldırmak ve AggregateException özelliğinin özgün özel durumları içermesini sağlamak amacıyla AggregateException.InnerExceptions yöntemini kullanabilirsiniz. Aşağıdaki örnekte iç içe AggregateException örnekler düzleştirilmiş ve tek bir döngüde işlenmiştir.
public static partial class Program
{
public static void FlattenTwo()
{
var task = Task.Factory.StartNew(() =>
{
var child = Task.Factory.StartNew(() =>
{
var grandChild = Task.Factory.StartNew(() =>
{
// This exception is nested inside three AggregateExceptions.
throw new CustomException("Attached child2 faulted.");
}, TaskCreationOptions.AttachedToParent);
// This exception is nested inside two AggregateExceptions.
throw new CustomException("Attached child1 faulted.");
}, TaskCreationOptions.AttachedToParent);
});
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var ex in ae.Flatten().InnerExceptions)
{
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
else
{
throw;
}
}
}
}
}
// The example displays the following output:
// Attached child1 faulted.
// Attached child2 faulted.
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Factory.StartNew(Sub()
Dim child1 = Task.Factory.StartNew(Sub()
Dim child2 = Task.Factory.StartNew(Sub()
Throw New CustomException("Attached child2 faulted.")
End Sub,
TaskCreationOptions.AttachedToParent)
Throw New CustomException("Attached child1 faulted.")
End Sub,
TaskCreationOptions.AttachedToParent)
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.Flatten().InnerExceptions
If TypeOf ex Is CustomException Then
Console.WriteLine(ex.Message)
Else
Throw
End If
Next
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' Attached child1 faulted.
' Attached child2 faulted.
Birden çok AggregateException.Flatten görev tarafından atılan birden fazla örnekteki iç istisnaları, aşağıdaki örnekte gösterildiği gibi, tek bir AggregateException örneğinde AggregateException yöntemini kullanarak yeniden fırlatabilirsiniz.
public static partial class Program
{
public static void TaskExceptionTwo()
{
try
{
ExecuteTasks();
}
catch (AggregateException ae)
{
foreach (var e in ae.InnerExceptions)
{
Console.WriteLine($"{e.GetType().Name}:\n {e.Message}");
}
}
}
static void ExecuteTasks()
{
// Assume this is a user-entered String.
string path = @"C:\";
List<Task> tasks = new();
tasks.Add(Task.Run(() =>
{
// This should throw an UnauthorizedAccessException.
return Directory.GetFiles(
path, "*.txt",
SearchOption.AllDirectories);
}));
tasks.Add(Task.Run(() =>
{
if (path == @"C:\")
{
throw new ArgumentException(
"The system root is not a valid path.");
}
return new string[] { ".txt", ".dll", ".exe", ".bin", ".dat" };
}));
tasks.Add(Task.Run(() =>
{
throw new NotImplementedException(
"This operation has not been implemented.");
}));
try
{
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
throw ae.Flatten();
}
}
}
// The example displays the following output:
// UnauthorizedAccessException:
// Access to the path 'C:\Documents and Settings' is denied.
// ArgumentException:
// The system root is not a valid path.
// NotImplementedException:
// This operation has not been implemented.
Imports System.Collections.Generic
Imports System.IO
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Try
ExecuteTasks()
Catch ae As AggregateException
For Each e In ae.InnerExceptions
Console.WriteLine("{0}:{2} {1}", e.GetType().Name, e.Message,
vbCrLf)
Next
End Try
End Sub
Sub ExecuteTasks()
' Assume this is a user-entered String.
Dim path = "C:\"
Dim tasks As New List(Of Task)
tasks.Add(Task.Run(Function()
' This should throw an UnauthorizedAccessException.
Return Directory.GetFiles(path, "*.txt",
SearchOption.AllDirectories)
End Function))
tasks.Add(Task.Run(Function()
If path = "C:\" Then
Throw New ArgumentException("The system root is not a valid path.")
End If
Return {".txt", ".dll", ".exe", ".bin", ".dat"}
End Function))
tasks.Add(Task.Run(Sub()
Throw New NotImplementedException("This operation has not been implemented.")
End Sub))
Try
Task.WaitAll(tasks.ToArray)
Catch ae As AggregateException
Throw ae.Flatten()
End Try
End Sub
End Module
' The example displays the following output:
' UnauthorizedAccessException:
' Access to the path 'C:\Documents and Settings' is denied.
' ArgumentException:
' The system root is not a valid path.
' NotImplementedException:
' This operation has not been implemented.
Ayrılmış alt görevlerden istisnalar
Varsayılan olarak, alt görevler bağımsız olarak oluşturulur. Ayrılmış görevlerden atılan istisnalar, anlık üst görevde ele alınmalı veya yeniden atılmalıdır; bunlar, ekli alt görevlerin geriye doğru yayılması gibi çağıran iş parçacığına iletilmez. En üstteki üst öğe, ayrılmış bir alt öğeden gelen bir özel durumu el ile yeniden oluşturabilir ve bunun bir AggregateException içinde sarmalanıp çağrılan iş parçacığına geri yayılmasına neden olabilir.
public static partial class Program
{
public static void DetachedTwo()
{
var task = Task.Run(() =>
{
var nestedTask = Task.Run(
() => throw new CustomException("Detached child task faulted."));
// Here the exception will be escalated back to the calling thread.
// We could use try/catch here to prevent that.
nestedTask.Wait();
});
try
{
task.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.Flatten().InnerExceptions)
{
if (e is CustomException)
{
Console.WriteLine(e.Message);
}
}
}
}
}
// The example displays the following output:
// Detached child task faulted.
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub()
Dim nestedTask1 = Task.Run(Sub()
Throw New CustomException("Detached child task faulted.")
End Sub)
' Here the exception will be escalated back to joining thread.
' We could use try/catch here to prevent that.
nestedTask1.Wait()
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.Flatten().InnerExceptions
If TypeOf ex Is CustomException Then
' Recover from the exception. Here we just
' print the message for demonstration purposes.
Console.WriteLine(ex.Message)
End If
Next
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' Detached child task faulted.
Çocuk görevde bir istisnayı gözlemlemek için bir devam işlemi kullansanız bile, istisna yine de üst görev tarafından gözlemlenmelidir.
İşbirliğine dayalı iptali gösteren özel durumlar
Bir görevdeki kullanıcı kodu bir iptal isteğine yanıt verdiğinde, doğru yöntem isteğin iletildiği iptal belirtecini kullanarak bir OperationCanceledException fırlatmaktır. Görev örneği, özel durumu yaymaya çalışmadan önce, özel durumdaki belirteci, görev örneği oluşturulduğunda kendisine geçirilen belirteçle karşılaştırır. Bunlar aynıysa, görev TaskCanceledExceptionAggregateException içinde sarmalanmış olarak aktarılır ve iç özel durumlar incelendiğinde bu görülebilir. Ancak, çağrıyı başlatan iş parçacığı görevde beklemiyorsa, bu özel durum iletilemez. Daha fazla bilgi için bkz. Görev İptali.
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task = Task.Factory.StartNew(() =>
{
CancellationToken ct = token;
while (someCondition)
{
// Do some work...
Thread.SpinWait(50_000);
ct.ThrowIfCancellationRequested();
}
},
token);
// No waiting required.
tokenSource.Dispose();
Dim someCondition As Boolean = True
Dim tokenSource = New CancellationTokenSource()
Dim token = tokenSource.Token
Dim task1 = Task.Factory.StartNew(Sub()
Dim ct As CancellationToken = token
While someCondition = True
' Do some work...
Thread.SpinWait(500000)
ct.ThrowIfCancellationRequested()
End While
End Sub,
token)
İç özel durumları filtrelemek için handle yöntemini kullanma
AggregateException.Handle yöntemini, başka bir mantık kullanmadan "işlenmiş" olarak değerlendirebileceğiniz özel durumları filtrelemek için kullanabilirsiniz.
AggregateException.Handle(Func<Exception,Boolean>) yöntemine sağlanan kullanıcı temsilcisinde, özel durumun türünü, Message özelliğini veya diğer ilgili bilgileri inceleyerek zararsız olup olmadığını belirleyebilirsiniz. Temsilcinin döndürdüğü tüm özel durumlar, yöntem döndürdüğünden false
hemen sonra AggregateException yeni AggregateException.Handle bir örnekte yeniden oluşturulur.
Aşağıdaki örnek, koleksiyondaki her özel durumu AggregateException.InnerExceptions inceleyen bu konudaki ilk örnekle işlevsel olarak eşdeğerdir. Bunun yerine, bu özel durum işleyicisi, her özel durum için AggregateException.Handle yöntem nesnesini çağırır ve yalnızca CustomException
örneği olmayan özel durumları yeniden fırlatır.
public static partial class Program
{
public static void HandleMethodThree()
{
var task = Task.Run(
() => throw new CustomException("This exception is expected!"));
try
{
task.Wait();
}
catch (AggregateException ae)
{
// Call the Handle method to handle the custom exception,
// otherwise rethrow the exception.
ae.Handle(ex =>
{
if (ex is CustomException)
{
Console.WriteLine(ex.Message);
}
return ex is CustomException;
});
}
}
}
// The example displays the following output:
// This exception is expected!
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Run(Sub() Throw New CustomException("This exception is expected!"))
Try
task1.Wait()
Catch ae As AggregateException
' Call the Handle method to handle the custom exception,
' otherwise rethrow the exception.
ae.Handle(Function(e)
If TypeOf e Is CustomException Then
Console.WriteLine(e.Message)
End If
Return TypeOf e Is CustomException
End Function)
End Try
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays the following output:
' This exception is expected!
Aşağıda, dosyaları numaralandırırken bir AggregateException.Handle istisnası için özel işlem sağlamak üzere UnauthorizedAccessException yöntemini kullanan daha eksiksiz bir örnek verilmiştir.
public static partial class Program
{
public static void TaskException()
{
// This should throw an UnauthorizedAccessException.
try
{
if (GetAllFiles(@"C:\") is { Length: > 0 } files)
{
foreach (var file in files)
{
Console.WriteLine(file);
}
}
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
{
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
}
Console.WriteLine();
// This should throw an ArgumentException.
try
{
foreach (var s in GetAllFiles(""))
{
Console.WriteLine(s);
}
}
catch (AggregateException ae)
{
foreach (var ex in ae.InnerExceptions)
Console.WriteLine($"{ex.GetType().Name}: {ex.Message}");
}
}
static string[] GetAllFiles(string path)
{
var task1 =
Task.Run(() => Directory.GetFiles(
path, "*.txt",
SearchOption.AllDirectories));
try
{
return task1.Result;
}
catch (AggregateException ae)
{
ae.Handle(x =>
{
// Handle an UnauthorizedAccessException
if (x is UnauthorizedAccessException)
{
Console.WriteLine(
"You do not have permission to access all folders in this path.");
Console.WriteLine(
"See your network administrator or try another path.");
}
return x is UnauthorizedAccessException;
});
return Array.Empty<string>();
}
}
}
// The example displays the following output:
// You do not have permission to access all folders in this path.
// See your network administrator or try another path.
//
// ArgumentException: The path is not of a legal form.
Imports System.IO
Imports System.Threading.Tasks
Module Example
Public Sub Main()
' This should throw an UnauthorizedAccessException.
Try
Dim files = GetAllFiles("C:\")
If files IsNot Nothing Then
For Each file In files
Console.WriteLine(file)
Next
End If
Catch ae As AggregateException
For Each ex In ae.InnerExceptions
Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message)
Next
End Try
Console.WriteLine()
' This should throw an ArgumentException.
Try
For Each s In GetAllFiles("")
Console.WriteLine(s)
Next
Catch ae As AggregateException
For Each ex In ae.InnerExceptions
Console.WriteLine("{0}: {1}", ex.GetType().Name, ex.Message)
Next
End Try
Console.WriteLine()
End Sub
Function GetAllFiles(ByVal path As String) As String()
Dim task1 = Task.Run(Function()
Return Directory.GetFiles(path, "*.txt",
SearchOption.AllDirectories)
End Function)
Try
Return task1.Result
Catch ae As AggregateException
ae.Handle(Function(x)
' Handle an UnauthorizedAccessException
If TypeOf x Is UnauthorizedAccessException Then
Console.WriteLine("You do not have permission to access all folders in this path.")
Console.WriteLine("See your network administrator or try another path.")
End If
Return TypeOf x Is UnauthorizedAccessException
End Function)
End Try
Return Array.Empty(Of String)()
End Function
End Module
' The example displays the following output:
' You do not have permission to access all folders in this path.
' See your network administrator or try another path.
'
' ArgumentException: The path is not of a legal form.
Task.Exception özelliğini kullanarak özel durumları gözlemleme
Bir görev TaskStatus.Faulted durumunda tamamlanırsa, hangi özel durumun hataya neden olduğunu bulmak için Exception özelliği incelenebilir. Özelliğini gözlemlemenin Exception iyi bir yolu, aşağıdaki örnekte gösterildiği gibi yalnızca öncül görev hatalarıyla çalışan bir devamlılık kullanmaktır.
public static partial class Program
{
public static void ExceptionPropagationTwo()
{
_ = Task.Run(
() => throw new CustomException("task1 faulted."))
.ContinueWith(_ =>
{
if (_.Exception?.InnerException is { } inner)
{
Console.WriteLine($"{inner.GetType().Name}: {inner.Message}");
}
},
TaskContinuationOptions.OnlyOnFaulted);
Thread.Sleep(500);
}
}
// The example displays output like the following:
// CustomException: task1 faulted.
Imports System.Threading
Imports System.Threading.Tasks
Module Example
Public Sub Main()
Dim task1 = Task.Factory.StartNew(Sub()
Throw New CustomException("task1 faulted.")
End Sub).
ContinueWith(Sub(t)
Console.WriteLine("{0}: {1}",
t.Exception.InnerException.GetType().Name,
t.Exception.InnerException.Message)
End Sub, TaskContinuationOptions.OnlyOnFaulted)
Thread.Sleep(500)
End Sub
End Module
Class CustomException : Inherits Exception
Public Sub New(s As String)
MyBase.New(s)
End Sub
End Class
' The example displays output like the following:
' CustomException: task1 faulted.
Anlamlı bir uygulamada, devamlılık temsilcisi özel durumla ilgili ayrıntılı bilgileri günlüğe kaydedebilir ve büyük olasılıkla özel durumdan kurtarmak için yeni görevler oluşturabiliyordu. Bir görev hata verirse, aşağıdaki ifadeler özel durum oluşturur:
await task
task.Wait()
task.Result
task.GetAwaiter().GetResult()
Oluşan özel durumları işlemek ve gözlemlemek için bir try-catch
deyimi kullanın. Alternatif olarak, Task.Exception özelliğine erişerek özel durumu gözlemleyin.
Önemli
Aşağıdaki ifadeler kullanıldığında AggregateException açıkça yakalanamaz.
await task
task.GetAwaiter().GetResult()
UnobservedTaskException olayını
Güvenilmeyen eklentiler barındırılırken olduğu gibi bazı senaryolarda zararsız özel durumlar yaygın olabilir ve bunların tümünü el ile gözlemlemek çok zor olabilir. Bu gibi durumlarda, TaskScheduler.UnobservedTaskException olayını işleyebilirsiniz. System.Threading.Tasks.UnobservedTaskExceptionEventArgs İşleyicinize geçirilen örnek, gözlemlenmeyen özel durumun birleştirilmiş iş parçacığına geri yayılmasını önlemek için kullanılabilir.