共用方式為


作法:接收 First-Chance 例外狀況通知

備註

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

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

事件會在應用程式域層級引發。 執行線程可以傳遞多個應用程式域,因此一個應用程式域中未處理的例外狀況可以在另一個應用程式域中處理。 通知會在已新增 事件的處理程式的每個應用程式域中發生,直到應用程式域處理例外狀況為止。

本文中的程式和範例示範如何在具有一個應用程式域的簡單程式中,以及在您所建立的應用程式域中接收第一次機會例外狀況通知。

如需跨越數個應用程式域的較複雜範例,請參閱 事件的範例 FirstChanceException

在預設應用程式域中接收 First-Chance 例外狀況通知

在下列程式中,應用程式 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 {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 {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()
    

在另一個應用程式域中接收 First-Chance 例外狀況通知

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

若要在您建立的應用程式領域中接收首次發生的例外狀況通知

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

    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. 建立應用程式域,並將事件處理程式新增至 FirstChanceException 該應用程式域的事件。 在這個範例中,應用程式域名稱為 AD1

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

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

在應用程式域中展示第一次機會例外通知

  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 {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 {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 中擲回例外狀況時,FirstChanceException 事件會在 AD1 中引發,而事件處理程式會顯示訊息。 執行時期接著會尋找例外處理程式。 在第一個案例中,會在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 {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

另請參閱