Share via


Afhandeling van uitzonderingen (taakparallelbibliotheek)

Niet-verwerkte uitzonderingen die worden gegenereerd door gebruikerscode die in een taak wordt uitgevoerd, worden doorgegeven aan de aanroepende thread, behalve in bepaalde scenario's die verderop in dit onderwerp worden beschreven. Uitzonderingen worden doorgegeven wanneer u een van de statische methoden of instantiemethoden Task.Wait gebruikt en u deze verwerkt door de aanroep in een try/catch instructie in te sluiten. Als een taak het bovenliggende element is van gekoppelde onderliggende taken of als u op meerdere taken wacht, kunnen er meerdere uitzonderingen optreden.

Als u alle uitzonderingen weer wilt doorgeven aan de aanroepende thread, verpakt de taakinfrastructuur deze in een AggregateException exemplaar. De AggregateException uitzondering heeft een InnerExceptions eigenschap die kan worden geïnventariseerd om alle oorspronkelijke uitzonderingen te onderzoeken die zijn gegenereerd, en om elk afzonderlijk te verwerken (of niet te verwerken). U kunt de oorspronkelijke uitzonderingen ook afhandelen met behulp van de AggregateException.Handle methode.

Zelfs als er slechts één uitzondering wordt gegenereerd, wordt deze nog steeds verpakt in een AggregateException uitzondering, zoals in het volgende voorbeeld wordt weergegeven.


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!

U kunt een onverwerkte uitzondering voorkomen door alleen de AggregateException binnenste uitzonderingen te ondervangen en geen enkele van de binnenste uitzonderingen te observeren. We raden u echter aan dit niet te doen, omdat het vergelijkbaar is met het vangen van het basistype Exception in niet-parallelle scenario's. Als u een uitzondering wilt ondervangen zonder specifieke acties uit te voeren om ermee te herstellen, kunt u uw programma in een onbepaalde status laten staan.

Als u de Task.Wait methode niet wilt aanroepen om te wachten op de voltooiing van een taak, kunt u ook de uitzondering van de AggregateException eigenschap van de taak Exception ophalen, zoals in het volgende voorbeeld wordt weergegeven. Zie de sectie Waarneemuitzondering met behulp van de eigenschap Task.Exception in dit onderwerp voor meer informatie.


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!

Let op

De voorgaande voorbeeldcode bevat een while lus die de eigenschap van Task.IsCompleted de taak controleert om te bepalen wanneer de taak is voltooid. Dit moet nooit worden gedaan in productiecode omdat deze zeer inefficiënt is.

Als u niet wacht op een taak die een uitzondering doorgeeft of toegang krijgt tot Exception de eigenschap, wordt de uitzondering geëscaleerd volgens het .NET-uitzonderingsbeleid wanneer de taak garbagecollection is.

Wanneer uitzonderingen zijn toegestaan om terug te bellen naar de samenvoegingsthread, is het mogelijk dat een taak bepaalde items blijft verwerken nadat de uitzondering is gegenereerd.

Notitie

Wanneer Just My Code is ingeschakeld, wordt Visual Studio in sommige gevallen verbroken op de regel die de uitzondering genereert en wordt er een foutbericht weergegeven met de tekst 'Uitzondering die niet wordt verwerkt door gebruikerscode'. Deze fout is goedaardig. U kunt op F5 drukken om door te gaan en het gedrag van uitzonderingsafhandeling te bekijken dat in deze voorbeelden wordt gedemonstreerd. Als u wilt voorkomen dat Visual Studio de eerste fout onderBreekt, schakelt u het selectievakje Just My Code inschakelen uit onder Extra, Opties, Foutopsporing, Algemeen.

Onderliggende taken en geneste AggregateExceptions gekoppeld

Als een taak een gekoppelde onderliggende taak heeft die een uitzondering genereert, wordt die uitzondering verpakt in een AggregateException voordat deze wordt doorgegeven aan de bovenliggende taak, die deze uitzondering zelf AggregateException verpakt voordat deze wordt doorgegeven aan de aanroepende thread. In dergelijke gevallen bevat de InnerExceptions eigenschap van de AggregateException uitzondering die wordt gevangen bij de Task.Wait, WaitAnyof WaitAll methode een of meer AggregateException exemplaren, niet de oorspronkelijke uitzonderingen die de fout hebben veroorzaakt. U kunt de methode gebruiken Flatten om alle geneste AggregateException uitzonderingen te AggregateException verwijderen, zodat de AggregateException.InnerExceptions eigenschap de oorspronkelijke uitzonderingen bevat. In het volgende voorbeeld worden geneste AggregateException exemplaren platgemaakt en in slechts één lus verwerkt.


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.

U kunt ook de AggregateException.Flatten methode gebruiken om de binnenste uitzonderingen van meerdere exemplaren die door meerdere AggregateException taken in één AggregateException exemplaar worden gegenereerd, opnieuw te werpen, zoals in het volgende voorbeeld wordt weergegeven.

public static partial class Program
{
    public static void TaskExceptionTwo()
    {
        try
        {
            ExecuteTasks();
        }
        catch (AggregateException ae)
        {
            foreach (var e in ae.InnerExceptions)
            {
                Console.WriteLine(
                    "{0}:\n   {1}", e.GetType().Name, 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.

Uitzonderingen van losgekoppelde onderliggende taken

Onderliggende taken worden standaard gemaakt als losgekoppeld. Uitzonderingen die worden veroorzaakt door losgekoppelde taken moeten worden verwerkt of opnieuw worden uitgevoerd in de bovenliggende taak; ze worden niet op dezelfde manier doorgegeven aan de aanroepende thread als gekoppelde onderliggende taken die worden doorgegeven. Het bovenste bovenliggende item kan een uitzondering van een losgekoppeld onderliggend element handmatig opnieuw plaatsen om ervoor te zorgen dat deze in een AggregateException thread wordt verpakt en weer wordt doorgegeven aan de aanroepende thread.


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.

Zelfs als u een vervolg gebruikt om een uitzondering in een onderliggende taak te observeren, moet de uitzondering nog steeds worden waargenomen door de bovenliggende taak.

Uitzonderingen die wijzen op collectieve annulering

Wanneer gebruikerscode in een taak reageert op een annuleringsaanvraag, is de juiste procedure het doorgeven OperationCanceledException van het annuleringstoken waarop de aanvraag is gecommuniceerd. Voordat de uitzondering wordt doorgegeven, vergelijkt de taakinstantie het token in de uitzondering met het token dat is doorgegeven toen deze werd gemaakt. Als ze hetzelfde zijn, wordt een verpakte taak in de AggregateExceptiontaak doorgegeven TaskCanceledException en kan deze worden weergegeven wanneer de binnenste uitzonderingen worden onderzocht. Als de aanroepende thread echter niet op de taak wacht, wordt deze specifieke uitzondering niet doorgegeven. Zie Taakannulering voor meer informatie.

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)

De handlemethode gebruiken om binnenste uitzonderingen te filteren

U kunt de AggregateException.Handle methode gebruiken om uitzonderingen te filteren die u als 'verwerkt' kunt behandelen zonder verdere logica te gebruiken. In de gemachtigde van de gebruiker die aan de AggregateException.Handle(Func<Exception,Boolean>) methode is verstrekt, kunt u het uitzonderingstype, Message de eigenschap ervan of andere informatie hierover bekijken, zodat u kunt bepalen of deze goedaardig is. Eventuele uitzonderingen waarvoor de gedelegeerde retourneertfalse, worden onmiddellijk nadat de AggregateException.Handle methode is geretourneerd, opnieuw in een nieuw AggregateException exemplaar geworpen.

Het volgende voorbeeld is functioneel gelijk aan het eerste voorbeeld in dit onderwerp, waarin elke uitzondering in de AggregateException.InnerExceptions verzameling wordt onderzocht. In plaats daarvan roept deze uitzonderingshandler het AggregateException.Handle methodeobject aan voor elke uitzondering en plaatst deze alleen uitzonderingen die geen CustomException exemplaren zijn.


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!

Hier volgt een completer voorbeeld waarin de AggregateException.Handle methode wordt gebruikt om speciale verwerking voor een UnauthorizedAccessException uitzondering te bieden bij het inventariseren van bestanden.

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(
                    "{0}: {1}", 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(
                    "{0}: {1}", 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.

Uitzonderingen observeren met behulp van de eigenschap Task.Exception

Als een taak in de status is voltooid, Exception kan de TaskStatus.Faulted eigenschap ervan worden onderzocht om te ontdekken welke specifieke uitzondering de fout heeft veroorzaakt. Een goede manier om de Exception eigenschap te observeren, is door een vervolg te gebruiken die alleen wordt uitgevoerd als de fout met de antecedent-taak optreedt, zoals wordt weergegeven in het volgende voorbeeld.


public static partial class Program
{
    public static void ExceptionPropagationTwo()
    {
        _ = Task.Run(
            () => throw new CustomException("task1 faulted."))
            .ContinueWith(_ =>
            {
                if (_.Exception?.InnerException is { } inner)
                {
                    Console.WriteLine("{0}: {1}",
                        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.

In een zinvolle toepassing kan de vervolgdelegatie gedetailleerde informatie over de uitzondering vastleggen en mogelijk nieuwe taken opgeven om van de uitzondering te herstellen. Als er een taakfout optreedt, genereert de volgende expressies de uitzondering:

  • await task
  • task.Wait()
  • task.Result
  • task.GetAwaiter().GetResult()

Gebruik een try-catch instructie om gegenereerde uitzonderingen te verwerken en te observeren. U kunt ook de uitzondering observeren door toegang te krijgen tot de Task.Exception eigenschap.

Belangrijk

Deze AggregateException kunnen niet expliciet worden opgevangen wanneer u de volgende expressies gebruikt:

  • await task
  • task.GetAwaiter().GetResult()

Gebeurtenis UnobservedTaskException

In sommige scenario's, zoals bij het hosten van niet-vertrouwde invoegtoepassingen, kunnen goedaardige uitzonderingen vaak voorkomen en kan het te moeilijk zijn om ze allemaal handmatig te observeren. In deze gevallen kunt u de TaskScheduler.UnobservedTaskException gebeurtenis afhandelen. Het System.Threading.Tasks.UnobservedTaskExceptionEventArgs exemplaar dat aan uw handler wordt doorgegeven, kan worden gebruikt om te voorkomen dat de niet-gereserveerde uitzondering wordt doorgegeven aan de samenvoegingsthread.

Zie ook