6

私はジェネリックの奇妙な振る舞いに出会った。以下は私がテストに使用するコードです。

public static class Program
{
    public static void Main()
    {
        Type listClassType = typeof(List<int>).GetGenericTypeDefinition();
        Type listInterfaceType = listClassType.GetInterfaces()[0];

        Console.WriteLine(listClassType.GetGenericArguments()[0].DeclaringType);
        Console.WriteLine(listInterfaceType.GetGenericArguments()[0].DeclaringType);
    }
}

出力:

System.Collections.Generic.List`1[T]
System.Collections.Generic.List`1[T]

ジェネリック型定義を使用しているため、2番目のConsole.WriteLine呼び出しがインターフェイスではなくクラスを表示するのは非常に奇妙であることがわかりました。これは正しい動作ですか?

コンパイラに汎用型推論を実装しようとしています。以下のコードがあるとします。

public static class GenericClass
{
    public static void GenericMethod<TMethodParam>(IList<TMethodParam> list) { }
}

そして、私はこのメソッドを次のように呼び出したいと思います。

GenericClass.GenericMethod(new List<int>());

推論の可能性を確認するために、メソッドシグネチャのタイプと渡された引数のタイプを比較する必要があります。しかし、以下のコードはfalseを返します。

typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType;

このような比較には、常にType.GetGenericTypeDefinitionを使用する必要がありますか?

4

2 に答える 2

15

どちらもTという名前の2つの異なるタイプを混同しています。次のように考えてください。

interface IFoo<TIFOO> { }
class Foo<TFOO> : IFoo<TFOO> {}

OK、一般的な型の定義Foo<int>何ですか?それはFoo<TFOO>です。

によって実装されるインターフェースFoo<TFOO>は何ですか?それはIFoo<TFOO>です。

型引数Foo<TFOO>何ですか?明らかにTFOO

どのタイプが宣言されました TFOOか? Foo<TFOO>それを宣言しました。

型引数IFoo<TFOO>何ですか?明らかにTFOO、ではありません TIFOO

どのタイプが宣言されました TFOOか? Foo<TFOO>それを宣言しました。 ではありません IFoo<TFOO>TFOOから来ていFooます。

わかる?

于 2013-03-26T16:50:50.130 に答える
2

2番目の質問を追加したため、2番目の回答を追加します。

コンパイラにジェネリック型推論を実装しようとしています...

したがって、リフレクションを使用してコンパイラーを構築していると思います。これは良い考えではないかもしれません。リフレクションは、初期の頃よりもはるかにパフォーマンスが向上していますが、トークンを直接操作する場合に比べて、依然として重量があります。また、反射放出は、タイプのすべての可能なトポロジーを放出できるわけではありません。ネストされた構造体タイプを含むいくつかのシナリオでは、混乱します。

代わりにCCIの使用を検討します。RoslynにはCCIの修正バージョンを使用しました。

以下のコードはfalseを返します。

typeof(GenericClass).GetMethods()[0].GetParameters()[0].ParameterType == listInterfaceType

そのとおりです。パラメータタイプはIList<TMethodParam>listInterfaceTypeありIList<T>、ここで、Tはで宣言された汎用パラメータタイプであり、で宣言された汎用パラメータタイプList<T>ではありませんIList<T>。それらはすべて異なるタイプです。

このような比較には、常にType.GetGenericTypeDefinitionを使用する必要がありますか?

2つのジェネリック型が両方とも同じジェネリック型の構造であるかどうかを確認したい場合は、はい。それがあなたがチェックしたいものでないなら、いいえ。

この型システムは複雑なので注意が必要です。

これは、リフレクションタイプのオブジェクトベースのアプローチではなく、トークンベースのアプローチを採用するもう1つの理由です。TypeDef手元にトークンがあると、aとaを区別するのがはるかに簡単になりTypeRefます。

于 2013-03-26T18:22:41.147 に答える