Share via


解析組件載入

.NET Framework 為需要更充分掌控組件載入的應用程式提供了 AppDomain.AssemblyResolve 事件。 藉由處理這個事件,您的應用程式就能從一般探查路徑將組件載入至載入內容、選取要載入的數個組件版本、發出動態組件及將它傳回等。 本主題提供處理 AssemblyResolve 事件的指引。

注意事項注意事項

若要解析僅限反映之內容中的組件負載,請改用 AppDomain.ReflectionOnlyAssemblyResolve 事件。

AssemblyResolve 事件的運作方式

當您為 AssemblyResolve 事件註冊處理常式時,處理常式會在執行階段無法藉由名稱繫結至組件時叫用。 例如,從使用者程式碼呼叫下列方法可能導致引發 AssemblyResolve 事件:

事件處理常式執行的工作

AssemblyResolve 事件的處理常式會接收 ResolveEventArgs.Name 屬性中,要載入之組件的顯示名稱。 如果處理常式無法辨識組件名稱,則會傳回 null (在 Visual Basic 中為 Nothing,在 Visual C++ 中則為 nullptr)。

如果處理常式可辨識組件名稱,則可以載入和傳回符合要求的組件。 下列清單描述一些範例情節。

  • 如果處理常式知道某個版本組件的位置,則可以使用 Assembly.LoadFromAssembly.LoadFile 方法載入組件,如果成功的話,也可以傳回載入的組件。

  • 如果處理常式可以存取儲存為位元組陣列的組件資料庫,則可以使用其中一個採用位元組陣列的 Assembly.Load 方法多載。

  • 處理常式可以產生動態組件並將它傳回。

注意事項注意事項

處理常式壁需將組件載入至載入來源內容、載入內容或無內容。如果處理常式使用 Assembly.ReflectionOnlyLoadAssembly.ReflectionOnlyLoadFrom 方法將組件載入至僅限反映內容,則引發 AssemblyResolve 事件的載入嘗試會失敗。

處理常式必須負責傳回適合的組件。 處理常式可以藉由將 ResolveEventArgs.Name 屬性值傳遞至 AssemblyName(String) 建構函式的方式,剖析所要求組件的顯示名稱。 從 .NET Framework 4 版開始,處理常式可以使用 ResolveEventArgs.RequestingAssembly 屬性判斷目前的要求是否相依於另一個組件。 這項資訊有助於識別將滿足相依性的組件。

事件處理常式可傳回與所要求版本不同的組件版本。

在大部分情況下,處理常式傳回的組件會出現在載入內容中,無論處理常式將它載入何種內容。 例如,如果處理常式使用 Assembly.LoadFrom 方法將組件載入至載入來源內容,當處理常式傳回組件時,該組件會出現在載入內容中。 不過,在下列情況下,當處理常式傳回組件時,該組件會顯示為無內容狀態:

如需有關內容的詳細資訊,請參閱 Assembly.LoadFrom(String) 方法多載。

同一個應用程式定義域中可以載入同一個組件的多個版本。 不建議您採用這個做法,因為這樣可能導致型別指派的問題。 請參閱組件載入的最佳作法

事件處理常式不應執行的工作

處理 AssemblyResolve 事件的首要規則就是,您不應該嘗試傳回無法辨識的組件。 當您撰寫處理常式時,應該知道哪些組件可能引發事件。 您的處理常式應針對其他組件傳回 null。

重要事項重要事項

從 .NET Framework 4 開始,會針對附屬組件引發 AssemblyResolve 事件。這項變更會影響針對舊版 .NET Framework 撰寫的事件處理常式 (如果處理常式嘗試解析所有組件載入要求)。忽略無法辨識之組件的事件處理常式則不受這項變更的影響:它們會傳回 null,並且遵循一般後援機制。

載入組件時,事件處理常式不可使用可能反覆引發 AssemblyResolve 事件的任何 AppDomain.LoadAssembly.Load 方法多載,因為這樣可能導致堆疊溢位 (請參考本主題前段提供的清單)。即使您針對載入要求提供例外狀況處理,這種情況仍然會發生,因為直到所有事件處理常式都傳回之後,才會擲回例外狀況。 因此,下列程式碼會在找不到 MyAssembly 時導致堆疊溢位:

Imports System
Imports System.Reflection

Class BadExample

    Shared Sub Main()

        Dim ad As AppDomain = AppDomain.CreateDomain("Test")
        AddHandler ad.AssemblyResolve, AddressOf MyHandler

        Try
            Dim obj As object = ad.CreateInstanceAndUnwrap(
                "MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
                "MyType")
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Sub

    Shared Function MyHandler(ByVal source As Object, _
                              ByVal e As ResolveEventArgs) As Assembly
        Console.WriteLine("Resolving {0}", e.Name)
        Return Assembly.Load(e.Name)
    End Function
End Class

' This example produces output similar to the following:
'
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'...
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
'
'Process is terminated due to StackOverflowException.
using System;
using System.Reflection;

class BadExample
{
    static void Main()
    {
        AppDomain ad = AppDomain.CreateDomain("Test");
        ad.AssemblyResolve += MyHandler;

        try
        {
            object obj = ad.CreateInstanceAndUnwrap(
                "MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
                "MyType");
        } 
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    static Assembly MyHandler(object source, ResolveEventArgs e) 
    {
        Console.WriteLine("Resolving {0}", e.Name);
        return Assembly.Load(e.Name);
    }
} 

/* This example produces output similar to the following:

Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
...
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null

Process is terminated due to StackOverflowException.
 */
using namespace System;
using namespace System::Reflection;

ref class Example
{
internal:
    static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e) 
    {
        Console::WriteLine("Resolving {0}", e->Name);
        return Assembly::Load(e->Name);
    }
};

void main()
{
    AppDomain^ ad = AppDomain::CreateDomain("Test");
    ad->AssemblyResolve += gcnew ResolveEventHandler(&Example::MyHandler);

    try
    {
        Object^ obj = ad->CreateInstanceAndUnwrap(
            "MyAssembly, version=1.2.3.4, culture=neutral, publicKeyToken=null",
            "MyType");
    } 
    catch (Exception^ ex)
    {
        Console::WriteLine(ex->Message);
    }
}

/* This example produces output similar to the following:

Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
...
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null
Resolving MyAssembly, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null

Process is terminated due to StackOverflowException.
 */

請參閱

其他資源

組件載入的最佳作法

使用應用程式定義域