3

私は小さなテンプレート言語 (Razor によく似ています) を書いています。テンプレートのコンパイルでしなければならないことの 1 つは、(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() に費やされることがわかりました。そのようなルックアップを行うためのより高速な方法はありますか?

私はすでにこれらの結果をキャッシュしているので、そのような解決策には興味がないことに注意してください。

4

2 に答える 2

1

いくつかの実験の後、私はそれ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);
于 2013-10-03T15:43:58.467 に答える
1

Common Compiler Infrastructureを使用して、リフレクションなしでアセンブリをスキャンし、列挙型のリストを作成できます。彼らのサイトから:

CCI メタデータ API を使用すると、アプリケーションは .NET アセンブリ、モジュール、およびデバッグ (PDB) ファイルを効率的に分析または変更できます。CCI メタデータは、.NET System.Reflection および System.Reflection.Emit API の機能をサポートしていますが、パフォーマンスは大幅に向上しています。また、どちらの .NET API でも利用できない追加機能も提供します。

次に、実際のタイプが必要な場合は、リストを呼び出しで使用できますAssembly.GetType()

于 2013-09-19T15:59:58.550 に答える