动态类型解析 - 多次调用 Type.GetType 或扫描程序集中的所有类型?

Dynamic type resolution - multiple calls to Type.GetType or scanning all types in assembly?

我目前正在实施类型名称解析方案。可用信息与您在常规 C# 源项目中获得的信息非常相似:

在 运行 时,对于每个要解析的类型名称,该名称要么是完全限定的(带有命名空间,但不带有程序集名称),要么是预计来自以下之一的简单名称using 个命名空间。

为了找到与每个标识符匹配的 Type,我正在考虑以下两种策略之一:

  1. 使用 Assembly.Load 预加载所有程序集并扫描所有类型。所有具有与 using 命名空间之一匹配的命名空间前缀的简单名称都将被预缓存。还创建了一个字典,将程序集中每个命名空间限定的类型名称直接映射到它的 Type。加载阶段会进行相应的冲突解决

  2. 不要预加载任何东西。每当类型名称到达时,请尝试以下顺序:

    • 假设名称是完全限定的;依次连接每个引用的程序集名称以创建程序集限定名称并调用 Type.GetType 以查看我们是否获得有效类型。

    • 如果上述步骤没有产生任何有效的类型并且名称没有前缀,则假定它是一个简单的名称;重复上述步骤,但每次都在简单名称前加上 using 命名空间之一,以查看我们是否获得有效类型。

哪种方法更可取,优缺点是什么?

目前还不清楚每个 运行 需要以这种方式解析多少类型,但我假设在 10 到 100 之间。可以在任何时候引用多个程序集,每个程序集可能有数百种类型。

我有兴趣了解这两种策略的相对表现,也很想知道处理这种情况的现有最佳实践。除了性能之外,了解行为副作用的任何差异将非常有帮助:例如,扫描 Assembly 中的所有类型是否会执行加载类型的所有静态构造函数?我更喜欢一种在 运行 引用程序集中的任何代码中尽可能惰性的方法。

事实证明,在新的 .NET Standard 中有一种更好的方法,即使用新的 System.Reflection.Metadata 命名空间。用他们自己的话说:

"This packages provides a low-level .NET (ECMA-335) metadata reader.

It's geared for performance and is the ideal choice for building higher-level libraries that intend to provide their own object model, such as compilers."

这是一个小代码片段,用于列出给定程序集文件中所有类型定义的名称和命名空间:

using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;

namespace MetadataTest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var stream = File.OpenRead(args[0]))
            using (var peFile = new PEReader(stream))
            {
                var metadataReader = peFile.GetMetadataReader();
                foreach (var type in metadataReader.TypeDefinitions)
                {
                    var definition = metadataReader.GetTypeDefinition(type);
                    var name = metadataReader.GetString(definition.Name);
                    var ns = metadataReader.GetString(definition.Namespace);
                    Console.WriteLine(ns + "." + name);
                }
            }
        }
    }
}