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
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
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
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
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
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 wMain()
, aby uzyskać odwołanie do domyślnej domeny aplikacji.
Aby zademonstrować powiadomienia o wyjątkach pierwszej szansy w domenie aplikacji
Utwórz obiekt
Worker
w domenie aplikacji utworzonej w poprzedniej procedurze. KlasaWorker
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)
Wywołaj metodę obiektu
Worker
, który zgłasza wyjątek. W tym przykładzie metodaThrower
jest wywoływana dwukrotnie. Po raz pierwszy argument metody jesttrue
, co powoduje, że metoda przechwyci własny wyjątek. Po raz drugi argument jestfalse
, a metodaMain()
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
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