AppDomain.FirstChanceException 事件
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
當在受管程式碼中拋出例外時,執行時執行時尚未在呼叫堆疊中搜尋應用程式域中的例外處理程序。
public:
event EventHandler<System::Runtime::ExceptionServices::FirstChanceExceptionEventArgs ^> ^ FirstChanceException;
public event EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs>? FirstChanceException;
public event EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs> FirstChanceException;
[add: System.Security.SecurityCritical]
[remove: System.Security.SecurityCritical]
public event EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs> FirstChanceException;
member this.FirstChanceException : EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs>
[<add: System.Security.SecurityCritical>]
[<remove: System.Security.SecurityCritical>]
member this.FirstChanceException : EventHandler<System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs>
Public Custom Event FirstChanceException As EventHandler(Of FirstChanceExceptionEventArgs)
事件類型
- 屬性
範例
以下範例建立一系列以 為 AD0 命名的 AD3應用域,每個應用域中都有一個 Worker 物件。 每個 Worker 物件都有指向下一個應用域的物件 Worker 的參考,唯獨最後一個應用程式域中的物件 Worker 例外。
FirstChanceException該AD1事件在除 之外的所有應用域中都被處理。
Note
除了這個示範多個應用域中首次機會異常通知的範例外,你還可以在 「如何:接收 First-Chance 異常通知」中找到簡單的使用案例。
當應用程式網域建立完成後,預設的應用程式域會呼叫 TestException 第一個應用程式網域的方法。 每個 Worker 物件會呼叫下一個應用程式域的方法 TestException ,直到最後一個 Worker 拋出一個異常,該異常可能是處理中或未處理。 因此,目前執行緒會經過所有應用域,並 TestException 加入每個應用域的堆疊。
當最後一個 Worker 物件處理例外時, FirstChanceException 事件只會在最後一個應用程式域中被觸發。 其他應用域從未有機會處理這個例外,因此事件不會被觸發。
當最後一個 Worker 物件未處理例外時, FirstChanceException 該事件會在每個有事件處理程序的應用域中被觸發。 每個事件處理程序完成後,堆疊會持續展開,直到例外被預設的應用程式域捕捉為止。
Note
若想看到堆疊顯示如何隨著事件越來越接近預設應用域而成長,請在事件處理程序中切換e.Exception.Message到 。e.ExceptionFirstChanceHandler 請注意,當 TestException 在應用程式域邊界被呼叫時,它會出現兩次:一次代理,一次代表存根。
using System;
using System.Reflection;
using System.Runtime.ExceptionServices;
class FirstChanceExceptionSnippet
{
static void Main()
{
AppDomain.CurrentDomain.FirstChanceException += FirstChanceHandler;
// Create a set of application domains, with a Worker object in each one.
// Each Worker object creates the next application domain.
AppDomain ad = AppDomain.CreateDomain("AD0");
Worker w = (Worker) ad.CreateInstanceAndUnwrap(
typeof(Worker).Assembly.FullName, "Worker");
w.Initialize(0, 3);
Console.WriteLine("\r\nThe last application domain throws an exception and catches it:");
Console.WriteLine();
w.TestException(true);
try
{
Console.WriteLine(
"\r\nThe last application domain throws an exception and does not catch it:");
Console.WriteLine();
w.TestException(false);
}
catch (ArgumentException ex)
{
Console.WriteLine("ArgumentException caught in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, ex.Message);
}
}
static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
{
Console.WriteLine("FirstChanceException event raised in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
}
}
public class Worker : MarshalByRefObject
{
private AppDomain ad = null;
private Worker w = null;
public void Initialize(int count, int max)
{
// Handle the FirstChanceException event in all application domains except
// AD1.
if (count != 1)
{
AppDomain.CurrentDomain.FirstChanceException += FirstChanceHandler;
}
// Create another application domain, until the maximum is reached.
// Field w remains null in the last application domain, as a signal
// to TestException().
if (count < max)
{
int next = count + 1;
ad = AppDomain.CreateDomain("AD" + next);
w = (Worker) ad.CreateInstanceAndUnwrap(
typeof(Worker).Assembly.FullName, "Worker");
w.Initialize(next, max);
}
}
public void TestException(bool handled)
{
// As long as there is another application domain, call TestException() on
// its Worker object. When the last application domain is reached, throw a
// handled or unhandled exception.
if (w != null)
{
w.TestException(handled);
}
else if (handled)
{
try
{
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
}
catch (ArgumentException ex)
{
Console.WriteLine("ArgumentException caught in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, ex.Message);
}
}
else
{
throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
}
}
static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
{
Console.WriteLine("FirstChanceException event raised in {0}: {1}",
AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
}
}
/* This example produces output similar to the following:
The last application domain throws an exception and catches it:
FirstChanceException event raised in AD3: Thrown in AD3
ArgumentException caught in AD3: Thrown in AD3
The last application domain throws an exception and does not catch it:
FirstChanceException event raised in AD3: Thrown in AD3
FirstChanceException event raised in AD2: Thrown in AD3
FirstChanceException event raised in AD0: Thrown in AD3
FirstChanceException event raised in Example.exe: Thrown in AD3
ArgumentException caught in Example.exe: Thrown in AD3
*/
open System
open System.Runtime.ExceptionServices
let firstChanceHandler _ (e: FirstChanceExceptionEventArgs) =
printfn $"FirstChanceException event raised in {AppDomain.CurrentDomain.FriendlyName}: {e.Exception.Message}"
type Worker() =
inherit MarshalByRefObject()
let mutable w = Unchecked.defaultof<Worker>
member _.Initialize(count, max) =
// Handle the FirstChanceException event in all application domains except
// AD1.
if count <> 1 then
AppDomain.CurrentDomain.FirstChanceException.AddHandler firstChanceHandler
// Create another application domain, until the maximum is reached.
// Field w remains null in the last application domain, as a signal
// to TestException().
if count < max then
let next = count + 1
let ad = AppDomain.CreateDomain("AD" + string next)
w <-
ad.CreateInstanceAndUnwrap(typeof<Worker>.Assembly.FullName, "Worker") :?> Worker
w.Initialize(next, max)
member _.TestException(handled) =
// As long as there is another application domain, call TestException() on
// its Worker object. When the last application domain is reached, throw a
// handled or unhandled exception.
if isNull (box w) then
w.TestException handled
elif handled then
try
raise (ArgumentException $"Thrown in {AppDomain.CurrentDomain.FriendlyName}")
with :? ArgumentException as ex ->
printfn $"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}"
else
raise (ArgumentException $"Thrown in {AppDomain.CurrentDomain.FriendlyName}")
AppDomain.CurrentDomain.FirstChanceException.AddHandler firstChanceHandler
// Create a set of application domains, with a Worker object in each one.
// Each Worker object creates the next application domain.
let ad = AppDomain.CreateDomain "AD0"
let w = ad.CreateInstanceAndUnwrap(typeof<Worker>.Assembly.FullName, "Worker") :?> Worker
w.Initialize(0, 3)
printfn "\nThe last application domain throws an exception and catches it:\n"
w.TestException true
try
printfn "\nThe last application domain throws an exception and does not catch it:\n"
w.TestException false
with :? ArgumentException as ex ->
printfn"ArgumentException caught in {AppDomain.CurrentDomain.FriendlyName}: {ex.Message}"
(* This example produces output similar to the following:
The last application domain throws an exception and catches it:
FirstChanceException event raised in AD3: Thrown in AD3
ArgumentException caught in AD3: Thrown in AD3
The last application domain throws an exception and does not catch it:
FirstChanceException event raised in AD3: Thrown in AD3
FirstChanceException event raised in AD2: Thrown in AD3
FirstChanceException event raised in AD0: Thrown in AD3
FirstChanceException event raised in Example.exe: Thrown in AD3
ArgumentException caught in Example.exe: Thrown in AD3
*)
Imports System.Reflection
Imports System.Runtime.ExceptionServices
Class Example
Shared Sub Main()
AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceHandler
' Create a set of application domains, with a Worker object in each one.
' Each Worker object creates the next application domain.
Dim ad As AppDomain = AppDomain.CreateDomain("AD0")
Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
GetType(Worker).Assembly.FullName, "Worker"),
Worker)
w.Initialize(0, 3)
Console.WriteLine(vbCrLf & "The last application domain throws an exception and catches it:")
Console.WriteLine()
w.TestException(true)
Try
Console.WriteLine(vbCrLf &
"The last application domain throws an exception and does not catch it:")
Console.WriteLine()
w.TestException(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
Private ad As AppDomain = Nothing
Private w As Worker = Nothing
Public Sub Initialize(ByVal count As Integer, ByVal max As Integer)
' Handle the FirstChanceException event in all application domains except
' AD1.
If count <> 1
AddHandler AppDomain.CurrentDomain.FirstChanceException, AddressOf FirstChanceHandler
End If
' Create another application domain, until the maximum is reached.
' Field w remains Nothing in the last application domain, as a signal
' to TestException().
If count < max
Dim nextAD As Integer = count + 1
ad = AppDomain.CreateDomain("AD" & nextAD)
w = CType(ad.CreateInstanceAndUnwrap(
GetType(Worker).Assembly.FullName, "Worker"),
Worker)
w.Initialize(nextAD, max)
End If
End Sub
Public Sub TestException(ByVal handled As Boolean)
' As long as there is another application domain, call TestException() on
' its Worker object. When the last application domain is reached, throw a
' handled or unhandled exception.
If w IsNot Nothing
w.TestException(handled)
Else If handled
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
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
' This example produces output similar to the following:
'
'The last application domain throws an exception and catches it:
'
'FirstChanceException event raised in AD3: Thrown in AD3
'ArgumentException caught in AD3: Thrown in AD3
'
'The last application domain throws an exception and does not catch it:
'
'FirstChanceException event raised in AD3: Thrown in AD3
'FirstChanceException event raised in AD2: Thrown in AD3
'FirstChanceException event raised in AD0: Thrown in AD3
'FirstChanceException event raised in Example.exe: Thrown in AD3
'ArgumentException caught in Example.exe: Thrown in AD3
備註
這個事件只是通知。 處理此事件不會處理該例外,也不影響後續的例外處理。 事件被提出且事件處理程序被呼叫後,通用語言執行時(CLR)開始尋找該例外的處理程序。 FirstChanceException 讓應用程式領域有優先檢視任何受管理例外的機會。
事件可依應用程式域處理。 如果執行緒在執行呼叫時經過多個應用程式域,該事件會在每個註冊事件處理程序的應用程式域中被觸發,然後 CLR 才開始搜尋該領域中匹配的例外處理程序。 事件處理完成後,會搜尋該應用域中匹配的例外處理程序。 若未找到,則在下一個應用域中觸發該事件。
你必須處理該事件處理 FirstChanceException 程序中出現的所有例外。 否則, FirstChanceException 則是遞迴提升。 這可能導致堆疊溢位並終止應用程式。 我們建議您為此事件實作受限執行區域(CER)的事件處理程序,以防止基礎設施相關的例外(如記憶體不足或堆疊溢位)在例外通知處理過程中影響虛擬機器。
除非事件處理程序具有安全性關鍵且擁有該 HandleProcessCorruptedStateExceptionsAttribute 屬性,否則不會因表示程序狀態損壞的例外(如存取違規)而觸發此事件。
通用語言執行時會在處理此通知事件時暫停執行緒中止。