【问题标题】:What's the fastest way to search for a type by name among loaded assemblies?在加载的程序集中按名称搜索类型的最快方法是什么?
【发布时间】:2013-09-19 15:32:00
【问题描述】:

我正在编写一种小型模板语言(很像 Razor),我在模板编译中必须做的一件事是根据 (1) 完全限定名称或 (2) 非限定名称来解析 CLR 枚举+ 命名空间。例如:

namespace Foo.Bar {
    public enum MyEnum { A, B }
}

// template:
@using Foo.Bar;
@using System;
...
@Foo.Bar.MyEnum.A // fully qualified
@MyEnum.A // unqualified, but in one of the specified namespaces

我目前的方法是扫描当前应用程序域中的所有程序集以查找枚举,如下所示:

string[] namespaces = // parsed from template
string typeName = // parsed from template
string fieldName = // parsed from template

var possibleResolutions = from type in AppDomain.CurrentDomain.GetAssemblies()
        .Where(a => !a.IsDynamic)
        .SelectMany(a => a.GetTypes())
    where type.IsEnum
    from @namespace in namespaces
    let fullName = @namespace + '.' + typeName
    // the replace is because nested enum types (like we have in AptOne, will have a fullname of namespace.OuterClass+InnerClass)
    where type.FullName.Replace('+', '.') == fullName
    let field = type.GetField(fieldName, BindingFlags.Public | BindingFlags.Static)
    where field != null;

我发现这在冷启动时可能会很慢(支配所有其他模板编译时间),几乎所有时间都花在 GetTypes() 中。我想知道,是否有更快的方法来进行此类查找?

请注意,我已经缓存了这些结果,所以我对那种解决方案不感兴趣。

【问题讨论】:

  • 有一个 good article 在 MSDN 上构建您自己的自定义活页夹,但我认为如果您尝试从程序集中的每个程序集中加载每种类型,您将不得不忍受缓慢范围。当然,您始终可以使用 Reflection.Emit 并让 .NET 编译器为您处理所有类型查找...

标签: c# performance reflection


【解决方案1】:

您可以使用Common Compiler Infrastructure 扫描程序集而不进行反射,以制作枚举列表。从他们的网站:

CCI 元数据 API 允许应用程序有效地分析或修改 .NET 程序集、模块和调试 (PDB) 文件。 CCI 元数据支持 .NET System.Reflection 和 System.Reflection.Emit API 的功能,但性能要好得多。它还提供了任何 .NET API 都没有的附加功能。

然后,如果您需要实际类型,您可以使用您的列表调用Assembly.GetType()

【讨论】:

    【解决方案2】:

    经过一些实验,我发现Assembly.GetType(string)Assembly.GetTypes().Where(...) 快得多。因此,我通过进行大量有针对性的名称查找并避免查看所有类型来解决我的性能问题:

    var result = AppDomain.CurrentDomain.GetAssemblies()
    .Where(a => !a.IsDynamic)
    .SelectMany(
                // possible full names is a list which tries replacing each . in the name with a +
                // starting from the end
        a => possibleFullNames.Select(t => new { t.@namespace, type = a.GetType(t.fullName) })
    )
    .Where(t => t.type != null);
    

    【讨论】:

      猜你喜欢
      • 2019-01-24
      • 1970-01-01
      • 2021-07-27
      • 1970-01-01
      • 2021-09-07
      • 2012-05-23
      • 2017-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多