2016-04-01 16 views
11

SomeGenericMethod<SomeGenericType<>>に電話できないのはなぜですか?ジェネリックメソッドをジェネリックメソッドに渡すにはどうすればよいですか?

class NotGeneric { } 

class Generic<T> { } 

class Program 
{ 
    static void Main(string[] args) 
    { 
     PrintType(typeof(NotGeneric)); 
     PrintType(typeof(Generic<>)); 
     PrintType<NotGeneric>(); 
     PrintType<Generic<>>(); // compiler goes crazy here 
    } 

    static void PrintType<T>() 
    { 
     Console.WriteLine(typeof(T)); 
    } 

    static void PrintType(Type t) 
    { 
     Console.WriteLine(t); 
    } 
} 
+0

基本的に 'typeof'はジェネリック型が定義されていないジェネリッククラス名をとることができますが、ジェネリック型として型を渡すと' Generic <> 'は完全に定義された型でなければなりません。 – juharr

+1

@juharrここにあるように、今のところ、最高の答えはコメントです。そうすることは不可能**と言うのは安全ですか? – talles

+0

私はrbaghbanliが同じことを言っていると思います。しかし、ジェネリック型として 'Generic <> 'を渡すことはできません。 'typeof(Generic )'を実行した場合、 'type 'は' typeof(Generic <>) 'に似ていますが、' GenericTypeParameters'は空の配列ではありません。 'typeof'は渡された型を記述するオブジェクトを提供します。 – juharr

答えて

2

私はSomeGenericMethod<SomeGenericType<>>

呼び出すことはできませんなぜ最も簡単な答えは:language specificationがそう言うので:

4.4構築のタイプ

ジェネリック型宣言、それ自体では、多くの異なるタイプを形成するための「青写真」として使用されるバインドされていないジェネリックタイプを示します型引数を適用する。型引数は、ジェネリック型の名前の直後に山括弧(<と>)で書かれています。少なくとも1つの型引数を含む型は、構築型と呼ばれます。構造型は、型名が現れる言語のほとんどの場所で使用できます。 バインドされていないジェネリック型は、typeof-expression(7.6.11)内でのみ使用できます。

4.4.3結合および非結合型

用語未結合のタイプは、非ジェネリック型または非結合ジェネリック型を指します。結合型という用語は、非ジェネリック型または構築型を指します。 バインドされていない型は、型宣言によって宣言されたエンティティを参照します。バインドされていないジェネリック型は、それ自体が型ではなく、変数、引数または戻り値の型として、または基本型として使用することはできません。 バインドされていないジェネリック型を参照できる唯一の構文は、typeof式(7.6.11)です。

なぜC#の仕様はそうですか? CLI specは、同様にその指示ので:ジェネリック型

...

をインスタンス化

II.9.4をCLIは、ジェネリック型の部分的インスタンス化をサポートしていません。ジェネリック型は、メタデータ署名ブロブのどこにでもインスタンス化されていてはならない。

[OK]を今すぐlegaleseで止めましょう。あなたの質問への実際の答えは:あなたが初めてSomeMethod<SomeType>()を呼び出すと

、CLRは、JITコンパイラを起動、SomeMethod<T>を読んであろう、Tに置き換え、そしてSomeMethod<SomeType>を表し新しい実行可能コードを作成します。

SomeMethod<SomeOtherType>()に電話すると、プロセスを繰り返す必要があります。新しいコードがSomeMethod<SomeOtherType>に生成されます。

Generic<>のようなバインドされていないジェネリックタイプの有効なコードを作成することはできません。一般的なケースでは、JITは、Tを知らなくても、どのコード表現を生成するかを知ることができません。

  • Tstringであり、あなたの方法は、タイプTのローカル変数を宣言する場合、JITは、スタック領域を割り当てるか、ネイティブポインタのサイズとレジスタを使用します。
  • TGuidの場合、JITは固定された128ビット値にスタック領域を割り当てる必要があります。 Tの内容がわからない場合は、コードを生成できません。

したがって、一般に、では、非結合型の実行可能コードを生成することはできません。なぜあなたは間違いなくでしたか?あなたが提供したスニペットの場合は、特別なケーシングが必要になり、PrintTypeメソッドにローカルTを追加した場合、呼び出しコードが機能しなくなります。ジェネリックはアセンブリ全体で再利用可能でなければならないため、呼び出しコードは呼び出されたメソッドについて何も想定できません。

+0

これが答えです。最終的には、JITコンパイラは、メソッド呼び出しで 'Generic <>'のために何を生成するのか分からないためです(JITコンパイルの "fault"です)。 – talles

-2

はこのような何かを試してみてください。

public class Generic<T> 
{ 
    public void PrintType(T param) 
    { 
     Console.WriteLine(param.GetType().Name); 
    } 
} 
+2

これは、 'PrintType ();' doesnt 'によって 'PrintType(typeof(Generic <>))'が動作するのはなぜですか? – juharr

+0

あなたは明らかに 'Generic <>'を使うことはできません。タイプを指定する必要があります。 'Generic ' –

+1

ですが、OPは実際に' typeof(Generic <>) 'がうまくいかない理由を本当に尋ねています。 – juharr

0
PrintType<Generic<YOU NEED TO PUT TYPE HERE>>(); 
+3

あなたは 'typeof(Generic <>)'を実行するのがなぜ大丈夫なのかという質問を見てください。 – juharr

+0

@juharrごめんなさい、彼にはたくさんの質問があります。 – skalinkin

7

コンパイラは、一般的な方法を専門とする専門的なタイプを必要としGeneric<>は、それが一般的なものであり、専門のではありません。したがって、Generic<>は型ですが、汎用メソッドの特殊化には特化されていません。

+0

'typeof(Generic <>)の' Generic <> 'はコンパイル時に解決されますか? – talles

+3

私が書いたように、 'Generic <>'は型ですので、 'typeof(Generic <>)'には問題ありません。これはジェネリック型です。ジェネリック型は特殊化されていないため、専門化には使用できません。 –