共用方式為


作法:接收第一個可能發生的例外狀況通知

注意

本文專屬於 .NET Framework。 其不適用於較新的 .NET 實作,包括 .NET 6 和更新版本。

AppDomain 類別的 FirstChanceException 事件可讓您在 Common Language Runtime 開始搜尋例外狀況處理常式之前,收到已擲回例外狀況的通知。

這個事件是在應用程式定義域層級引發。 執行的執行緒可以通過多個應用程式定義域;因此,在另一個應用程式定義域中無法處理某個應用程式定義域中未處理的例外狀況。 在應用程式定義域處理例外狀況之前,通知都會發生在每個已新增事件之處理常式的應用程式定義域中。

本文中的程序和範例示範如何接收具有一個應用程式定義域的簡單程式中以及您所建立之應用程式定義域中第一個可能發生傳回型別的例外狀況通知。

如需跨數個應用程式定義域的更複雜範例,請參閱 FirstChanceException 事件的範例。

接收預設應用程式定義域中第一個可能發生傳回型別的例外狀況通知

在下列程序中,應用程式的進入點 (Main() 方法) 會在預設應用程式定義域中執行。

示範預設應用程式定義域中第一個可能發生傳回型別的例外狀況通知

  1. 使用 Lambda 函式定義 FirstChanceException 事件的事件處理常式,並將它附加至事件。 在此範例中,事件處理常式會列印已處理事件之應用程式定義域的名稱以及例外狀況的 Message 屬性。

    using System;
    using System.Runtime.ExceptionServices;
    
    class Example
    {
        static void Main()
        {
            AppDomain.CurrentDomain.FirstChanceException +=
                (object source, FirstChanceExceptionEventArgs e) =>
                {
                    Console.WriteLine("FirstChanceException event raised in {0}: {1}",
                        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. 擲回並攔截例外狀況。 執行階段找到例外狀況處理常式之前,會引發 FirstChanceException 事件,並顯示訊息。 此訊息接在例外狀況處理常式所顯示的訊息後面。

    try
    {
        throw new ArgumentException("Thrown in " + AppDomain.CurrentDomain.FriendlyName);
    }
    catch (ArgumentException ex)
    {
        Console.WriteLine("ArgumentException caught in {0}: {1}",
            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. 擲回但不會攔截例外狀況。 執行階段尋找例外狀況處理常式之前,會引發 FirstChanceException 事件,並顯示訊息。 沒有任何例外狀況處理常式,因此應用程式會終止。

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

    此程序的前三個步驟所示的程式碼會形成完整主控台應用程式。 應用程式的輸出會根據 .exe 檔案的名稱而不同,因為預設應用程式定義域的名稱包含 .exe 檔案的名稱和副檔名。 請參閱下面以取得範例輸出。

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

接收另一個應用程式定義域中第一個可能發生傳回型別的例外狀況通知

如果您的程式包含多個應用程式定義域,您可以選擇哪些應用程式網域會收到通知。

接收您所建立之應用程式定義域中第一個可能發生傳回型別的例外狀況通知

  1. 定義 FirstChanceException 事件的事件處理常式。 此範例使用 static 方法 (在 Visual Basic 中為 Shared 方法),這個方法會列印已處理事件之應用程式定義域的名稱以及例外狀況的 Message 屬性。

    static void FirstChanceHandler(object source, FirstChanceExceptionEventArgs e)
    {
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
            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. 建立應用程式定義域,並將事件處理常式新增至該應用程式定義域的 FirstChanceException 事件。 在此範例中,應用程式定義域命名為 AD1

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

    您可以使用相同的方式在預設應用程式定義域中處理此事件。 在 Main() 中使用 static (在 Visual Basic 中為 Shared) AppDomain.CurrentDomain 屬性,以取得預設應用程式定義域的參考。

示範應用程式定義域中第一個可能發生傳回型別的例外狀況通知

  1. 在您於上一個程序建立的應用程式定義域中建立 Worker 物件。 Worker 類別必須是公用,而且必須衍生自 MarshalByRefObject,如本文結尾的完整範例所示。

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(
                            typeof(Worker).Assembly.FullName, "Worker");
    
    Dim w As Worker = CType(ad.CreateInstanceAndUnwrap(
                                GetType(Worker).Assembly.FullName, "Worker"),
                            Worker)
    
  2. 呼叫可擲回例外狀況之 Worker 物件的方法。 在此範例中,會呼叫 Thrower 方法兩次。 第一次,方法引數是 true,可讓方法攔截它自己的例外狀況。 第二次,引數是 false,而 Main() 方法會攔截預設應用程式定義域中的例外狀況。

    // 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 {0}: {1}",
            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. 將程式碼放在 Thrower 方法中,以控制方法是否處理它自己的例外狀況。

    if (catchException)
    {
        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);
    }
    
    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
    

範例

下列範例會建立名為 AD1 的應用程式定義域,並將事件處理常式新增至應用程式定義域的 FirstChanceException 事件。 此範例會在應用程式定義域中建立 Worker 類別的執行個體,並呼叫名為 Thrower 且擲回 ArgumentException 的方法。 根據其引數的值,方法會攔截例外狀況或無法處理它。

每次 Thrower 方法在 AD1 中擲回例外狀況時,都會在 AD1 中引發 FirstChanceException 事件,而且事件處理常式會顯示訊息。 執行階段接著會尋找例外狀況處理常式。 在第一個案例中,例外狀況處理常式位於 AD1 中。 在第二個案例中,此例外狀況未在 AD1 中處理,而是改為在預設應用程式定義域中攔截。

注意

預設應用程式定義域的名稱與可執行檔的名稱相同。

如果您將 FirstChanceException 事件的處理常式新增至預設應用程式定義域,則會引發事件,並在預設應用程式定義域處理例外狀況之前處理事件。 若要查看其運作,請在 Main() 開頭新增 C# 程式碼 AppDomain.CurrentDomain.FirstChanceException += FirstChanceException; (在 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 {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
{
    public void Thrower(bool catchException)
    {
        if (catchException)
        {
            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);
        }
    }
}

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

另請參閱