Udostępnij za pośrednictwem


Instrukcje: odbieranie powiadomień o wyjątkach First-Chance

Uwaga

Ten artykuł jest specyficzny dla programu .NET Framework. Nie ma zastosowania do nowszych implementacji platformy .NET, w tym .NET 6 i nowszych wersji.

Zdarzenie FirstChanceException klasy AppDomain umożliwia odbieranie powiadomienia o wystąpieniu wyjątku, zanim środowisko uruchomieniowe języka wspólnego rozpoczęło wyszukiwanie procedur obsługi wyjątków.

Zdarzenie jest wywoływane na poziomie domeny aplikacji. Wątek wykonywania może przechodzić przez wiele domen aplikacji, więc wyjątek, który nie jest obsługiwany w jednej domenie aplikacji, może być obsługiwany w innej domenie aplikacji. Powiadomienie występuje w każdej domenie aplikacji, która dodała procedurę obsługi zdarzenia, aż do momentu, gdy jedna z domen aplikacji obsłuży wyjątek.

Procedury i przykłady w tym artykule pokazują, jak otrzymywać powiadomienia o wyjątkach pierwszej szansy w prostym programie, który ma jedną domenę aplikacji i w utworzonej domenie aplikacji.

Aby uzyskać bardziej złożony przykład obejmujący kilka domen aplikacji, zobacz przykład zdarzenia FirstChanceException.

Odbieranie powiadomień o wyjątkach First-Chance w domyślnej domenie aplikacji

W poniższej procedurze punkt wejścia dla aplikacji, metoda Main(), jest uruchamiany w domyślnej domenie aplikacji.

Aby zademonstrować powiadomienia o wyjątkach pierwszej szansy w domyślnej domenie aplikacji

  1. Zdefiniuj program obsługi zdarzeń dla zdarzenia FirstChanceException przy użyciu funkcji lambda i dołącz go do zdarzenia. W tym przykładzie program obsługi zdarzeń wyświetla nazwę domeny aplikacji, w której obsłużono zdarzenie, oraz właściwość Message wyjątku.

    using System;
    using System.Runtime.ExceptionServices;
    
    class Example
    {
        static void Main()
        {
            AppDomain.CurrentDomain.FirstChanceException +=
                (object source, FirstChanceExceptionEventArgs e) =>
                {
                    Console.WriteLine($"FirstChanceException event raised in {AppDomain.CurrentDomain.FriendlyName}: {e.Exception.Message}");
                };
    
    Imports System.Runtime.ExceptionServices
    
    Class Example
    
        Shared Sub Main()
    
            AddHandler AppDomain.CurrentDomain.FirstChanceException,
                       Sub(source As Object, e As FirstChanceExceptionEventArgs)
                           Console.WriteLine("FirstChanceException event raised in {0}: {1}",
                                             AppDomain.CurrentDomain.FriendlyName,
                                             e.Exception.Message)
                       End Sub
    
  2. Wyrzuć wyjątek i przechwyć go. Zanim środowisko uruchomieniowe zlokalizuje program obsługi wyjątków, zostanie zgłoszone zdarzenie FirstChanceException i zostanie wyświetlony komunikat. Po tym komunikacie jest wyświetlany komunikat programu obsługi wyjątków.

    try
    {
        throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine($"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}");
    }
    
    Try
        Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
    
    Catch ex As ArgumentException
    
        Console.WriteLine("ArgumentException caught in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, ex.Message)
    End Try
    
  3. Wyrzuć wyjątek, ale go nie przechwyć. Zanim środowisko uruchomieniowe wyszukuje program obsługi wyjątków, zdarzenie FirstChanceException jest zgłaszane i wyświetla komunikat. Nie ma procedury obsługi wyjątków, więc aplikacja kończy działanie.

            throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
        }
    }
    
            Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
        End Sub
    End Class
    

    Kod przedstawiony w pierwszych trzech krokach tej procedury tworzy kompletną aplikację konsolową. Dane wyjściowe aplikacji różnią się w zależności od nazwy pliku .exe, ponieważ nazwa domyślnej domeny aplikacji składa się z nazwy i rozszerzenia pliku .exe. Zobacz następujące informacje, aby uzyskać przykładowe dane wyjściowe.

    /* This example produces output similar to the following:
    
    FirstChanceException event raised in Example.exe: Thrown in Example.exe
    ArgumentException caught in Example.exe: Thrown in Example.exe
    FirstChanceException event raised in Example.exe: Thrown in Example.exe
    
    Unhandled Exception: System.ArgumentException: Thrown in Example.exe
       at Example.Main()
     */
    
    ' This example produces output similar to the following:
    '
    'FirstChanceException event raised in Example.exe: Thrown in Example.exe
    'ArgumentException caught in Example.exe: Thrown in Example.exe
    'FirstChanceException event raised in Example.exe: Thrown in Example.exe
    '
    'Unhandled Exception: System.ArgumentException: Thrown in Example.exe
    '   at Example.Main()
    

Odbieranie powiadomień o wyjątkach First-Chance w innej domenie aplikacji

Jeśli program zawiera więcej niż jedną domenę aplikacji, możesz wybrać, które domeny aplikacji odbierają powiadomienia.

Aby otrzymywać powiadomienia o wyjątkach pierwszej szansy w utworzonej domenie aplikacji

  1. Zdefiniuj program obsługi zdarzeń dla zdarzenia FirstChanceException. W tym przykładzie użyto metody static (metodaShared w języku Visual Basic), która wyświetla nazwę domeny aplikacji, w której obsłużono zdarzenie, oraz właściwość Message wyjątku.

    static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine($"FirstChanceException event raised in {AppDomain.CurrentDomain.FriendlyName}: {e.Exception.Message}");
    }
    
    Shared Sub FirstChanceHandler(ByVal source As Object,
                                  ByVal e As FirstChanceExceptionEventArgs)
    
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message)
    End Sub
    
  2. Utwórz domenę aplikacji i dodaj procedurę obsługi zdarzeń do zdarzenia FirstChanceException dla tej domeny aplikacji. W tym przykładzie domena aplikacji ma nazwę AD1.

    AppDomain ad = AppDomain.CreateDomain("AD1");
    ad.FirstChanceException += FirstChanceHandler;
    
    Dim ad As AppDomain = AppDomain.CreateDomain("AD1")
    AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler
    

    To zdarzenie można obsłużyć w domyślnej domenie aplikacji w taki sam sposób. Użyj właściwości static (Shared w języku Visual Basic) AppDomain.CurrentDomain w Main(), aby uzyskać odwołanie do domyślnej domeny aplikacji.

Aby zademonstrować powiadomienia o wyjątkach pierwszej szansy w domenie aplikacji

  1. Utwórz obiekt Worker w domenie aplikacji utworzonej w poprzedniej procedurze. Klasa Worker musi być publiczna i musi pochodzić z MarshalByRefObject, jak pokazano w kompletnym przykładzie na końcu tego artykułu.

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            typeof(Worker).Assembly.FullName, "Worker");
    
    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                GetType(Worker).Assembly.FullName, "Worker"),
                            Worker)
    
  2. Wywołaj metodę obiektu Worker, który zgłasza wyjątek. W tym przykładzie metoda Thrower jest wywoływana dwukrotnie. Po raz pierwszy argument metody jest true, co powoduje, że metoda przechwyci własny wyjątek. Po raz drugi argument jest false, a metoda Main() przechwytuje wyjątek w domyślnej domenie aplikacji.

    // The worker throws an exception and catches it.
    w.Thrower(true);
    
    try
    {
        // The worker throws an exception and doesn't catch it.
        w.Thrower(false);
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine($"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}");
    }
    
    ' The worker throws an exception and catches it.
    w.Thrower(true)
    
    Try
        ' The worker throws an exception and doesn't catch it.
        w.Thrower(false)
    
    Catch ex As ArgumentException
    
        Console.WriteLine("ArgumentException caught in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, ex.Message)
    End Try
    
  3. Umieść kod w metodzie Thrower, aby kontrolować, czy metoda obsługuje własny wyjątek.

    if (catchException)
    {
        try
        {
            throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}");
        }
    }
    else
    {
        throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
    }
    
    If catchException
    
        Try
            Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
    
        Catch ex As ArgumentException
    
            Console.WriteLine("ArgumentException caught in {0}: {1}",
                AppDomain.CurrentDomain.FriendlyName, ex.Message)
        End Try
    Else
    
        Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
    End If
    

Przykład

Poniższy przykład tworzy domenę aplikacji o nazwie AD1 i dodaje procedurę obsługi zdarzeń do zdarzenia FirstChanceException domeny aplikacji. Przykład tworzy wystąpienie klasy Worker w domenie aplikacji i wywołuje metodę o nazwie Thrower, która zgłasza ArgumentException. W zależności od wartości argumentu metoda przechwytuje wyjątek lub nie może go obsłużyć.

Za każdym razem, gdy metoda Thrower zgłasza wyjątek w AD1, zdarzenie FirstChanceException jest zgłaszane w AD1, a program obsługi zdarzeń wyświetla komunikat. Następnie środowisko uruchomieniowe wyszukuje procedurę obsługi wyjątków. W pierwszym przypadku program obsługi wyjątków znajduje się w AD1. W drugim przypadku wyjątek nie jest obsługiwany w AD1, lecz przechwytywany w domyślnej domenie aplikacji.

Uwaga

Nazwa domyślnej domeny aplikacji jest taka sama jak nazwa pliku wykonywalnego.

Jeśli dodasz program obsługi zdarzenia FirstChanceException do domyślnej domeny aplikacji, zdarzenie zostanie zgłoszone i obsłużone, zanim domyślna domena aplikacji obsłuży wyjątek. Aby to zobaczyć, na początku Main()dodaj kod C# AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (w Visual Basic AddHandler AppDomain.CurrentDomain.FirstChanceException, FirstChanceException).

using System;
using System.Reflection;
using System.Runtime.ExceptionServices;

class Example
{
    static void Main()
    {
        // To receive first chance notifications of exceptions in
        // an application domain, handle the FirstChanceException
        // event in that application domain.
        AppDomain ad = AppDomain.CreateDomain("AD1");
        ad.FirstChanceException += FirstChanceHandler;

        // Create a worker object in the application domain.
        Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                                typeof(Worker).Assembly.FullName, "Worker");

        // The worker throws an exception and catches it.
        w.Thrower(true);

        try
        {
            // The worker throws an exception and doesn't catch it.
            w.Thrower(false);
        }
        catch (ArgumentException ex)
        {
            Console.WriteLine($"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}");
        }
    }

    static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine($"FirstChanceException event raised in {AppDomain.CurrentDomain.FriendlyName}: {e.Exception.Message}");
    }
}

public class Worker : MarshalByRefObject
{
    public void Thrower(bool catchException)
    {
        if (catchException)
        {
            try
            {
                throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
            }
            catch (ArgumentException ex)
            {
                Console.WriteLine($"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}");
            }
        }
        else
        {
            throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
        }
    }
}

/* This example produces output similar to the following:

FirstChanceException event raised in AD1: Thrown in AD1
ArgumentException caught in AD1: Thrown in AD1
FirstChanceException event raised in AD1: Thrown in AD1
ArgumentException caught in Example.exe: Thrown in AD1
 */
Imports System.Reflection
Imports System.Runtime.ExceptionServices

Class Example
    Shared Sub Main()

        ' To receive first chance notifications of exceptions in 
        ' an application domain, handle the FirstChanceException
        ' event in that application domain.
        Dim ad As AppDomain = AppDomain.CreateDomain("AD1")
        AddHandler ad.FirstChanceException, AddressOf FirstChanceHandler


        ' Create a worker object in the application domain.
        Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                    GetType(Worker).Assembly.FullName, "Worker"),
                                Worker)

        ' The worker throws an exception and catches it.
        w.Thrower(true)

        Try
            ' The worker throws an exception and doesn't catch it.
            w.Thrower(false)

        Catch ex As ArgumentException

            Console.WriteLine("ArgumentException caught in {0}: {1}",
                AppDomain.CurrentDomain.FriendlyName, ex.Message)
        End Try
    End Sub

    Shared Sub FirstChanceHandler(ByVal source As Object,
                                  ByVal e As FirstChanceExceptionEventArgs)

        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            AppDomain.CurrentDomain.FriendlyName, e.Exception.Message)
    End Sub
End Class

Public Class Worker
    Inherits MarshalByRefObject

    Public Sub Thrower(ByVal catchException As Boolean)

        If catchException

            Try
                Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)

            Catch ex As ArgumentException

                Console.WriteLine("ArgumentException caught in {0}: {1}",
                    AppDomain.CurrentDomain.FriendlyName, ex.Message)
            End Try
        Else

            Throw New ArgumentException("Thrown in " & AppDomain.CurrentDomain.FriendlyName)
        End If
    End Sub
End Class

' This example produces output similar to the following:
'
'FirstChanceException event raised in AD1: Thrown in AD1
'ArgumentException caught in AD1: Thrown in AD1
'FirstChanceException event raised in AD1: Thrown in AD1
'ArgumentException caught in Example.exe: Thrown in AD1

Zobacz też