Procedura: Esaminare il contenuto dell'assembly usando MetadataLoadContext

L'API reflection in .NET per impostazione predefinita consente agli sviluppatori di esaminare il contenuto degli assembly caricati nel contesto di esecuzione principale. Tuttavia, a volte non è possibile caricare un assembly nel contesto di esecuzione, ad esempio perché è stato compilato per un'altra piattaforma o architettura del processore o è un assembly di riferimento. L'API System.Reflection.MetadataLoadContext consente di caricare ed esaminare tali assembly. Gli assembly caricati in MetadataLoadContext vengono considerati solo come metadati, ovvero è possibile esaminare i tipi nell'assembly, ma non è possibile eseguire codice in esso contenuto. A differenza del contesto di esecuzione principale, non MetadataLoadContext carica automaticamente le dipendenze dalla directory corrente, ma usa la logica di associazione personalizzata fornita dall'oggetto MetadataAssemblyResolver passato.

Prerequisiti

Per usare MetadataLoadContext, installare il pacchetto NuGet System.Reflection.MetadataLoadContext . È supportato in qualsiasi framework di destinazione conforme a .NET Standard 2.0, ad esempio .NET Core 2.0 o .NET Framework 4.6.1.

Creare MetadataAssemblyResolver per MetadataLoadContext

La creazione di MetadataLoadContext richiede la fornitura dell'istanza di MetadataAssemblyResolver. Il modo più semplice per specificarne uno consiste nell'usare , PathAssemblyResolverche risolve gli assembly dalla raccolta specificata di stringhe di percorso dell'assembly. Questa raccolta, oltre agli assembly da esaminare direttamente, deve includere anche tutte le dipendenze necessarie. Ad esempio, per leggere l'attributo personalizzato che si trova in un assembly esterno, è necessario includere tale assembly o verrà generata un'eccezione. Nella maggior parte dei casi, è necessario includere almeno l'assembly principale, ovvero l'assembly contenente tipi di sistema predefiniti, ad esempio System.Object. Il codice seguente illustra come creare l'oggetto PathAssemblyResolver usando la raccolta costituita dall'assembly ispezionato e dall'assembly principale del runtime corrente:

var resolver = new PathAssemblyResolver(new string[] { "ExampleAssembly.dll", typeof(object).Assembly.Location });

Se è necessario accedere a tutti i tipi BCL, è possibile includere tutti gli assembly di runtime nella raccolta. Il codice seguente illustra come creare l'oggetto PathAssemblyResolver usando la raccolta costituita dall'assembly ispezionato e da tutti gli assembly del runtime corrente:

// Get the array of runtime assemblies.
string[] runtimeAssemblies = Directory.GetFiles(RuntimeEnvironment.GetRuntimeDirectory(), "*.dll");

// Create the list of assembly paths consisting of runtime assemblies and the inspected assembly.
var paths = new List<string>(runtimeAssemblies);
paths.Add("ExampleAssembly.dll");

// Create PathAssemblyResolver that can resolve assemblies using the created list.
var resolver = new PathAssemblyResolver(paths);

Creare MetadataLoadContext

Per creare , richiamare il MetadataLoadContextcostruttore MetadataLoadContext(MetadataAssemblyResolver, String), passando l'oggetto creato MetadataAssemblyResolver in precedenza come primo parametro e il nome dell'assembly di base come secondo parametro. È possibile omettere il nome dell'assembly principale, nel qual caso il costruttore tenterà di usare i nomi predefiniti: "mscorlib", "System.Runtime" o "netstandard".

Dopo aver creato il contesto, è possibile caricare gli assembly in esso usando metodi come LoadFromAssemblyPath. È possibile usare tutte le API di reflection sugli assembly caricati, ad eccezione di quelle che comportano l'esecuzione del codice. Il GetCustomAttributes metodo comporta l'esecuzione dei costruttori, quindi usare il GetCustomAttributesData metodo quando è necessario esaminare gli attributi personalizzati in MetadataLoadContext.

L'esempio di codice seguente crea MetadataLoadContext, carica l'assembly in esso e restituisce gli attributi dell'assembly nella console:

var mlc = new MetadataLoadContext(resolver);

using (mlc)
{
    // Load assembly into MetadataLoadContext.
    Assembly assembly = mlc.LoadFromAssemblyPath("ExampleAssembly.dll");
    AssemblyName name = assembly.GetName();

    // Print assembly attribute information.
    Console.WriteLine($"{name.Name} has following attributes: ");

    foreach (CustomAttributeData attr in assembly.GetCustomAttributesData())
    {
        try
        {
            Console.WriteLine(attr.AttributeType);
        }
        catch (FileNotFoundException ex)
        {
            // We are missing the required dependency assembly.
            Console.WriteLine($"Error while getting attribute type: {ex.Message}");
        }
    }
}

Se è necessario testare i tipi in MetadataLoadContext per verificarne l'uguaglianza o l'assegnabilità, usare solo gli oggetti di tipo caricati in tale contesto. La combinazione MetadataLoadContext di tipi con tipi di runtime non è supportata. Si consideri, ad esempio, un tipo testedType in MetadataLoadContext. Se è necessario verificare se un altro tipo è assegnabile da esso, non usare codice come typeof(MyType).IsAssignableFrom(testedType). Usare invece codice simile al seguente:

Assembly matchAssembly = mlc.LoadFromAssemblyPath(typeof(MyType).Assembly.Location);
Type matchType = assembly.GetType(typeof(MyType).FullName!)!;

if (matchType.IsAssignableFrom(testedType))
{
    Console.WriteLine($"{nameof(matchType)} is assignable from {nameof(testedType)}");
}

Esempio

Per un esempio di codice completo, vedere l'esempio Inspect assembly contents using MetadataLoadContext .For a complete code example, see the Inspect assembly contents using MetadataLoadContext sample.

Vedi anche