Aracılığıyla paylaş


Derleme yüklerini çözme

.NET, derleme yükleme üzerinde daha fazla denetim gerektiren uygulamalar için olayı sağlar AppDomain.AssemblyResolve . Uygulamanız bu olayı işleyerek normal yoklama yollarının dışından bir derlemeyi yük bağlamı içine yükleyebilir, yüklenecek birkaç derleme sürümünü seçebilir, dinamik bir derleme yayınlayabilir ve döndürebilir vb. Bu konu, olayı işlemeye AssemblyResolve yönelik rehberlik sağlar.

Not

Derleme yüklerini yalnızca yansıma bağlamında çözümlemek için bunun yerine olayını kullanın AppDomain.ReflectionOnlyAssemblyResolve .

AssemblyResolve olayı nasıl çalışır?

Olay için bir işleyici kaydettiğinizde AssemblyResolve , çalışma zamanı ada göre bir derlemeye bağlanamadığında işleyici çağrılır. Örneğin, kullanıcı kodundan aşağıdaki yöntemleri çağırmak AssemblyResolve olayın tetik edilmesine neden olabilir:

Olay işleyicisi ne yapar?

Olay işleyicisi AssemblyResolve , özelliğinde ResolveEventArgs.Name yüklenecek derlemenin görünen adını alır. İşleyici derleme adını tanımıyorsa (C#), (Visual Basic) Nothing veya nullptr (Visual C++) döndürür null .

İşleyici derleme adını tanırsa, isteği karşılayan bir derlemeyi yükleyip döndürebilir. Aşağıdaki listede bazı örnek senaryolar açıklanmaktadır.

  • İşleyici derlemenin bir sürümünün konumunu biliyorsa, veya Assembly.LoadFile yöntemini kullanarak derlemeyi Assembly.LoadFrom yükleyebilir ve başarılı olursa yüklenen derlemeyi döndürebilir.

  • İşleyicinin bayt dizileri olarak depolanan bir derleme veritabanına erişimi varsa, bayt dizisi alan yöntem aşırı yüklemelerinden Assembly.Load birini kullanarak bayt dizisini yükleyebilir.

  • İşleyici dinamik bir derleme oluşturabilir ve döndürebilir.

Not

İşleyici, derlemeyi yük bağlamı içine, yük bağlamı içine veya bağlam olmadan yüklemelidir. İşleyici, veya yöntemini kullanarak Assembly.ReflectionOnlyLoad derlemeyi yalnızca yansıma bağlamı içine Assembly.ReflectionOnlyLoadFrom yüklerse, olayı tetikleyen AssemblyResolve yük girişimi başarısız olur.

Uygun bir derleme döndürmek olay işleyicisinin sorumluluğundadır. İşleyici, özellik değerini AssemblyName(String) oluşturucuya geçirerek istenen derlemenin ResolveEventArgs.Name görünen adını ayrıştırabilir. .NET Framework 4'le başlayarak işleyici, geçerli isteğin ResolveEventArgs.RequestingAssembly başka bir derlemenin bağımlılığı olup olmadığını belirlemek için özelliğini kullanabilir. Bu bilgiler, bağımlılığı karşılayan bir derlemenin tanımlanmasına yardımcı olabilir.

Olay işleyicisi, derlemenin istenen sürümden farklı bir sürümünü döndürebilir.

Çoğu durumda, işleyici tarafından döndürülen derleme, işleyicinin yüklediği bağlamdan bağımsız olarak yük bağlamında görünür. Örneğin, işleyici bir derlemeyi Assembly.LoadFrom yükten bağlama yüklemek için yöntemini kullanıyorsa, işleyici onu döndürdüğünde derleme yük bağlamında görünür. Ancak, aşağıdaki durumda işleyici onu döndürdüğünde derleme bağlam olmadan görünür:

Bağlamlar hakkında bilgi için bkz Assembly.LoadFrom(String) . yöntem aşırı yüklemesi.

Aynı derlemenin birden çok sürümü aynı uygulama etki alanına yüklenebilir. Tür atama sorunlarına neden olabileceği için bu uygulama önerilmez. Bkz. Derleme yükleme için en iyi yöntemler.

Olay işleyicisinin yapmaması gerekenler

Olayı işlemeye yönelik AssemblyResolve birincil kural, tanımadığınız bir derlemeyi döndürmeyi denememektir. İşleyiciyi yazarken, olayın tetiklenmesine neden olabilecek derlemeleri bilmeniz gerekir. İşleyiciniz diğer derlemeler için null döndürmelidir.

Önemli

.NET Framework 4'le başlayarak, AssemblyResolve olay uydu derlemeleri için tetiklenir. İşleyici tüm derleme yük isteklerini çözümlemeye çalışırsa, bu değişiklik .NET Framework'ün önceki bir sürümü için yazılmış bir olay işleyicisini etkiler. Tanımadıkları derlemeleri yoksayan olay işleyicileri bu değişiklikten etkilenmez: döndürürler nullve normal geri dönüş mekanizmaları izlenir.

Bir derlemeyi yüklerken, olay işleyicisi AppDomain.Load olayın özyinelemeli olarak yükseltilmesine neden AssemblyResolve olabilecek veya Assembly.Load yöntemi aşırı yüklemelerinden hiçbirini kullanmamalıdır, çünkü bu bir yığın taşmasına neden olabilir. (Bu konunun önceki bölümlerinde sağlanan listeye bakın.) Tüm olay işleyicileri döndürülene kadar özel durum oluşturmadığından yük isteği için özel durum işleme sağlasanız bile bu durum oluşur. Bu nedenle, aşağıdaki kod bulunamazsa MyAssembly yığın taşmasıyla sonuçlanır:

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);
        // DO NOT DO THIS: This causes a StackOverflowException
        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.
 */
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)
        // DO NOT DO THIS: This causes a StackOverflowException
        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 namespace System;
using namespace System::Reflection;

ref class Example
{
internal:
    static Assembly^ MyHandler(Object^ source, ResolveEventArgs^ e)
    {
        Console::WriteLine("Resolving {0}", e->Name);
        // DO NOT DO THIS: This causes a StackOverflowException
        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.
*/

AssemblyResolve'ı işlemenin doğru yolu

Olay işleyicisinden AssemblyResolve derlemeleri çözümlerken, işleyici veya AppDomain.Load yöntemini çağırırsa Assembly.Load sonunda bir StackOverflowException oluşturulur. Bunun yerine, olayı tetiklemediği AssemblyResolve için veya LoadFrom yöntemlerini kullanınLoadFile.

MyAssembly.dll Yürütme derlemesinin yakınında, bilinen bir konumda yer aldığını, derlemenin yolu verildiğinde çözümlenebileceğini Assembly.LoadFile düşünün.

using System;
using System.IO;
using System.Reflection;

class CorrectExample
{
    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);

        var path = Path.GetFullPath("../../MyAssembly.dll");
        return Assembly.LoadFile(path);
     }
}
Imports System.IO
Imports System.Reflection

Class CorrectExample

    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)

        Dim fullPath = Path.GetFullPath("../../MyAssembly.dll")
        Return Assembly.LoadFile(fullPath)
    End Function
End Class
using namespace System;
using namespace System::IO;
using namespace System::Reflection;

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

        String^ fullPath = Path::GetFullPath("../../MyAssembly.dll");
        return Assembly::LoadFile(fullPath);
    }
};

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);
    }
}

Ayrıca bkz.