【问题标题】:Dynamic type resolution - multiple calls to Type.GetType or scanning all types in assembly?动态类型解析 - 多次调用 Type.GetType 或扫描程序集中的所有类型?
【发布时间】:2016-11-22 22:56:02
【问题描述】:

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

  • Assembly 参考列表
  • using 命名空间列表

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

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

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

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

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

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

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

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

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

【问题讨论】:

  • 我相信这是XY problem。如果您能解释一下您要通过此实现的目标会更有用,因为也许您正在尝试重新发明方轮。或者谁知道。告诉我们您的问题背后的要求。
  • @MatíasFidemraizer 我正在考虑一种脚本语言的动态类型解析策略,并且希望更熟悉将名称映射到类型及其含义的可能策略。我绝不想暗示我有解决问题的方法,但我确实想列出我想到的方法。很高兴了解任何其他可能性。
  • 您在创建脚本语言吗?
  • 是的,目前就是这样。
  • 嗯,脚本语言应该使用动态语言运行时来实现。您是否尝试使用常规 CLR 实现一个?

标签: c# .net .net-assembly system.reflection type-resolution


【解决方案1】:

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

“这个包提供了一个低级的.NET(ECMA-335)元数据阅读器。

它专为性能而设计,是构建的理想选择 打算提供自己的对象模型的高级库, 比如编译器。”

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-07
    • 1970-01-01
    • 2018-04-27
    • 2012-04-23
    • 1970-01-01
    相关资源
    最近更新 更多