如何:使用 MetadataLoadContext 檢查組件內容

.NET 中的反映 API 預設可讓開發人員檢查載入主要執行內容中的組件內容。 不過,有時候無法將組件載入執行內容,例如因為已針對另一個平台或處理器架構對該組件編譯,或者它是參考組件System.Reflection.MetadataLoadContext API 可讓您載入和檢查這類組件。 載入至 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,請叫用其建構函式 MetadataLoadContext(MetadataAssemblyResolver, String),並將先前建立的 MetadataAssemblyResolver 做為第一個參數傳遞,並將核心組件名稱做為第二個參數傳遞。 您可以省略核心組件名稱,在此情況下,建構函式會嘗試使用預設名稱:"mscorlib"、"System.Runtime" 或 "netstandard"。

建立內容之後,可使用 LoadFromAssemblyPath 之類的方法來將組件載入其中。 可在載入的組件上使用所有的反映 API,但涉及程式碼執行的除外。 GetCustomAttributes 方法確實涉及建構函式的執行,因此當您需要檢查 MetadataLoadContext 中的自訂屬性時,請改用 GetCustomAttributesData 方法。

下列程式碼範例會建立 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)}");
}

範例

如需完整的程式碼範例,請參閱使用 MetadataLoadCoNtext 檢查組件內容範例

另請參閱