10

現在のAppDomainのすべての型を一覧表示すると、ジェネリック型とジェネリックプレースホルダーが表示されます。ただし、ジェネリック型を型でインスタンス化してから、appDomain内のすべての型を一覧表示すると、新しく作成された閉じた型が表示されません。

以下の例では、出力は次のとおりです。

Foo`1[T]

クローズドタイプを探しています:

Foo`1[System.Int32]

開いているジェネリック型に基づいてランタイムが作成した閉じた型を確認する方法はありますか?

class Foo<T>
{
}

class Program
{
    static void Main(string[] args)
    {
        var tmp = new Foo<int>();
        ListTypes();
    }

    private static void ListTypes()
    {
        var types = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                        from type in assembly.GetTypes()
                        where type.Name.Contains("Foo")
                        select type;

        foreach (var type in types)
            Console.WriteLine(type.ToString());
    }
}

また、閉じた型を発見することを期待して、一般的な引数ですべての型を見つけようとしました。

class Foo<T>
{
}

class Bar
{
}

class Program
{
    static void Main(string[] args)
    {
        var tmp = new Foo<Bar>();
        ListTypes();
    }

    private static void ListTypes()
    {
        var types = from assembly in AppDomain.CurrentDomain.GetAssemblies()
                        from type in assembly.GetTypes()
                        where type.IsGenericType
                        && type.GetGenericArguments().Contains(typeof(Bar))
                        select type;

        foreach (var type in types)
            Console.WriteLine(type.ToString());
    }
}

これは私の好奇心を満たすためだけのものです。

4

2 に答える 2

5

私が理解できる限り、この場合Foo<T>はオープンでバインドされていないジェネリック型であるため、実行時に CLR はそれをブループリント/スケルトンとして使用して、指定された型パラメーター型 ( 、 など) でジェネリック型を構築して閉じFoo<int>ますFoo<object>。したがって、基本的にFoo<int>はランタイムで構築されたFoo<T>スケルトンの実装です。

ここで、実行時にorFoo<int>を使用していずれかのタイプを取得できますが、それは同じではなく、意味がありません。しかし、よく見ると、とが同じメタデータ トークンと GUIDを共有していることがわかります。typeof(Foo<int>)typeof(Foo<>).MakeGenericType(new[] { typeof(int) })Typetypeof(Foo<T>)typeof(Foo<int>)

もう 1 つの興味深い点は、それtypeof(Foo<int>).Assemblyが期待どおりになることですが、既にお気付きのように、アセンブリからその型を取得することはできません。

これFoo<int>は、 がアセンブリで定義されていないためです (アセンブリ メタデータは Reflector/ILSpy で確認できます)。Foo<T>実行時に、CLR はforの特殊化された (「閉じた」) バージョンを作成 (「構築」)しFoo<int>(そのように構築された、無制限のオープン ジェネリック型定義の閉じた型)、それにType. そのため、CLR が実行時に生成するクローズ ジェネリック型のリストをなんらかの方法で直接公開しない限り、うまくいきません。

また、ここに私が言っていることを確認するかもしれないスニペットがあります:

Node< Form > や Node< String > などのジェネリック型の各構造には独自の型 ID がありますが、CLR は型のインスタンス化間で実際の JIT コンパイル コードの多くを再利用できます。これにより、コードの肥大化が大幅に削減されます。これは、ジェネリック型のさまざまなインスタンス化が実行時に展開されるためです。コンパイル時に構築された型に存在するのは、型参照だけです。アセンブリ A と B の両方が 3 番目のアセンブリで定義されたジェネリック型を参照する場合、それらの構築された型は実行時に展開されます。つまり、CLR の型 ID を共有するだけでなく (適切な場合)、アセンブリ A と B からの型のインスタンス化は、ネイティブ コードや拡張されたメタデータなどのランタイム リソースも共有します。

http://msdn.microsoft.com/en-us/magazine/cc163683.aspx

于 2012-10-10T21:58:16.577 に答える
1

Ivan の答えはほぼ正しいですが、アセンブリ メタデータには構築された型に関する情報が含まれていないと主張するのは正しくありません。構築されたすべての型は、それらを使用するアセンブリで定義され、Mono.Cecilなどのツールで確認できます。構築された型はリフレクションによって公開されず、Mono.Cecil でさえそれらすべてを見つけるのは非常に困難です。

基本的に、アセンブリで使用されるすべての型(プロパティの型、戻り値の型、ローカル変数の型など) を確認する必要があります。この情報はアセンブリ メタデータに含まれており、Mono.Cecil でかなり簡単に列挙できます。次に、型が構築されているかどうかを検出する単純なフィルターを適用するだけです。ジェネリック型定義から構築されたすべての型を見つけるために、ジェネリック型定義を参照するいくつかのアセンブリをたどる必要がある場合があることに注意してください。

このソリューションには 2 つの制限があります。まず、リフレクションを介して構築された型は、当然、どのアセンブリにも表示されません。次に、一部の構築型はジェネリック型/メソッドに埋め込まれており、それらのジェネリック型引数は、親の型/メソッドが特定のジェネリック型引数でインスタンス化された後にのみ認識されます。

于 2013-05-15T15:23:23.843 に答える