Sdílet prostřednictvím


Postupy: Příjem oznámení o výjimce First-Chance

Poznámka:

Tento článek je specifický pro rozhraní .NET Framework. Nevztahuje se na novější implementace .NET, včetně .NET 6 a novějších verzí.

Událost FirstChanceException třídy AppDomain umožňuje obdržet oznámení, že došlo k výjimce dříve, než modul CLR (Common Language Runtime) začal hledat obslužné rutiny výjimek.

Událost se vyvolá na úrovni domény aplikace. Vlákno provádění může procházet několika aplikačními doménami, takže výjimka, která je neošetřená v jedné aplikační doméně, by mohla být zpracována v jiné aplikační doméně. K oznámení dochází v každé doméně aplikace, která přidala obslužnou rutinu události, dokud doména aplikace nezpracuje výjimku.

Postupy a příklady v tomto článku ukazují, jak přijímat oznámení o výjimce první šance v jednoduchém programu, který má jednu doménu aplikace a v doméně aplikace, kterou vytvoříte.

Složitější příklad, který zahrnuje několik domén aplikace, najdete v příkladu události FirstChanceException.

Příjem oznámení o výjimce First-Chance ve výchozí doméně aplikace

V následujícím postupu se vstupní bod aplikace, metoda Main(), spouští ve výchozí doméně aplikace.

Pro předvedení oznámení o výjimce první šance ve výchozí doméně aplikace

  1. Definujte obslužnou rutinu události pro FirstChanceException událost pomocí funkce lambda a připojte ji k události. V tomto příkladu obslužná rutina události vytiskne název domény aplikace, kde byla událost zpracována, a vlastnost Message výjimky.

    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. Vyvolá výjimku a zachytí ji. Než modul runtime vyhledá obslužnou rutinu výjimky, vyvolá se událost FirstChanceException a zobrazí zprávu. Za touto zprávou následuje zpráva zobrazená obslužnou rutinou výjimky.

    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. Vyvolejte výjimku, ale nezachyťte ji. Než modul runtime začne vyhledávat obslužnou rutinu pro výjimky, je vyvolána událost FirstChanceException a zobrazí se zpráva. Neexistuje žádná obslužná rutina výjimky, takže aplikace je ukončena.

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

    Kód zobrazený v prvních třech krocích tohoto postupu tvoří úplnou konzolovou aplikaci. Výstup aplikace se liší v závislosti na názvu souboru .exe, protože název výchozí domény aplikace se skládá z názvu a přípony souboru .exe. Ukázkový výstup najdete v následujícím příkladu.

    /* 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()
    

Příjem oznámení o výjimce First-Chance v jiné doméně aplikace

Pokud váš program obsahuje více než jednu doménu aplikace, můžete zvolit, které domény aplikace přijímají oznámení.

Chcete-li přijímat oznámení o výjimkách první šance v aplikační doméně, kterou vytvoříte

  1. Definujte obslužnou proceduru pro událost FirstChanceException. Tento příklad používá metodu static (metodaShared v jazyce Visual Basic), která vytiskne název domény aplikace, kde byla událost zpracována, a vlastnost Message výjimky.

    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. Vytvořte doménu aplikace a přidejte obslužnou rutinu události do FirstChanceException události pro danou doménu aplikace. V tomto příkladu má doména aplikace název AD1.

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

    Tuto událost můžete zpracovat ve výchozí doméně aplikace stejným způsobem. Pomocí vlastnosti static (Shared v jazyce Visual Basic) AppDomain.CurrentDomain v Main() získejte odkaz na výchozí doménu aplikace.

Předvedení oznámení o výjimce první šance v doméně aplikace

  1. Vytvořte objekt Worker v doméně aplikace, kterou jste vytvořili v předchozím postupu. Třída Worker musí být veřejná a musí být odvozena od MarshalByRefObject, jak je znázorněno v úplném příkladu na konci tohoto článku.

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            typeof(Worker).Assembly.FullName, "Worker");
    
    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                GetType(Worker).Assembly.FullName, "Worker"),
                            Worker)
    
  2. Zavolejte metodu objektu Worker, která vyvolá výjimku. V tomto příkladu se metoda Thrower volá dvakrát. Poprvé je argument metody true, což způsobí, že metoda zachytí vlastní výjimku. Druhý argument je falsea metoda Main() zachytí výjimku ve výchozí doméně aplikace.

    // 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. Umístěte kód do Thrower metody, abyste mohli řídit, jestli metoda zpracovává vlastní výjimku.

    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
    

Příklad

Následující příklad vytvoří doménu aplikace s názvem AD1 a přidá obslužnou rutinu události do FirstChanceException události domény aplikace. Příklad vytvoří instanci třídy Worker v doméně aplikace a volá metodu s názvem Thrower, která vyvolá ArgumentException. V závislosti na hodnotě argumentu metoda buď zachytí výjimku, nebo ji nezpracuje.

Pokaždé, když metoda Thrower vyvolá výjimku ve AD1, je událost FirstChanceException vyvolána v AD1a obslužná rutina události zobrazí zprávu. Modul runtime pak vyhledá obslužnou rutinu výjimky. V prvním případě se obslužná rutina výjimky nachází v AD1. V druhém případě je výjimka neošetřená v AD1a místo toho je zachycena ve výchozí doméně aplikace.

Poznámka:

Název výchozí domény aplikace je stejný jako název spustitelného souboru.

Pokud přidáte obslužnou rutinu události FirstChanceException do výchozí domény aplikace, událost se vyvolá a zpracuje před tím, než výchozí doména aplikace zpracuje výjimku. Pokud to chcete vidět, přidejte na začátek Main()kód jazyka C# AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (v jazyce 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

Viz také