如何:使用 MetadataLoadContext 检查程序集内容

默认情况下,.NET 中的反射 API 使开发人员能够检查加载到主执行上下文中的程序集的内容。 但是,有时无法将程序集加载到执行上下文中,例如,因为它已针对其他平台或处理器体系结构进行编译,或者它是 引用程序集。 API System.Reflection.MetadataLoadContext 允许加载和检查此类程序集。 加载到其中的 MetadataLoadContext 程序集仅被视为元数据,也就是说,可以检查程序集中的类型,但不能执行其中包含的任何代码。 与主执行上下文不同, MetadataLoadContext 它不会自动从当前目录加载依赖项;而是使用传递给它的自定义绑定逻辑 MetadataAssemblyResolver

先决条件

若要使用 MetadataLoadContext,请安装 System.Reflection.MetadataLoadContext NuGet 包。 它受任何符合 .NET Standard 2.0 的目标框架的支持,例如 .NET Core 2.0 或 .NET Framework 4.6.1。

为 MetadataLoadContext 创建 MetadataAssemblyResolver

创建MetadataLoadContext需要提供MetadataAssemblyResolver的实例。 最简单的方法是使用 PathAssemblyResolver 从给定的程序集路径字符串集合中解析程序集。 除了要直接检查的程序集外,此集合还应包括所有所需的依赖项。 例如,若要读取位于外部程序集中的自定义属性,应包含该程序集,否则将导致异常被抛出。 在大多数情况下,至少应包含 核心程序集,即包含内置系统类型的程序集,例如 System.Object。 以下代码演示了如何使用由被检查的程序集和当前运行时的核心程序集组成的集合来创建PathAssemblyResolver

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

如果需要访问所有 BCL 类型,则可以在集合中包含所有运行时程序集。 以下代码展示了如何使用由检查过的程序集和当前运行时的所有程序集组成的集合来创建 PathAssemblyResolver

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

创建 MetadataLoadContext

要创建MetadataLoadContext,请调用其构造函数,将之前创建的MetadataAssemblyResolver作为第一个参数传递,并将核心程序集名称作为第二个参数传递。 可以省略核心程序集名称,在这种情况下,构造函数将尝试使用默认名称:“mscorlib”、“System.Runtime”或“netstandard”。

创建上下文后,可以使用诸如以下 LoadFromAssemblyPath方法将程序集加载到其中。 可以在加载的程序集上使用所有反射 API,但涉及代码执行的情况除外。 该方法GetCustomAttributes涉及构造函数的执行,因此,在需要检查自定义GetCustomAttributesData属性时,请改用该方法MetadataLoadContext

以下代码示例创建 MetadataLoadContext、将程序集加载到其中,并将程序集属性输出到控制台中:

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

如果需要测试类型 MetadataLoadContext 是否相等或可分配,则仅使用加载到该上下文中的类型对象。 不支持将MetadataLoadContext类型与运行时类型混合。 例如,考虑MetadataLoadContext中的类型testedType。 如果需要测试另一种类型是否可从中分配,请不要使用类似 typeof(MyType).IsAssignableFrom(testedType)代码。 请改用如下所示的代码:

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

Example

有关完整的代码示例,请参阅 使用 MetadataLoadContext 示例检查程序集内容

另请参阅