2017-04-13 8 views
1

私は、参照型はすべて同じ構築クラスを使用することを読んだ:C# - 建設クラスのTypeオブジェクトは

ジェネリック医薬品は、参照型では異なるやや働きます。最初にジェネリック型を参照型で構成すると、ランタイムは、MSIL内のパラメータの代わりにオブジェクト参照を持つ特殊ジェネリック型を作成します。次に、構成タイプが参照タイプをパラメーターとしてインスタンス化されるたびに、そのタイプにかかわらず、ランタイムは以前に作成された汎用タイプの特殊バージョンを再利用します。これはすべての参照が同じサイズであるため可能です。 (Generics in the Run Time (C# Programming Guide)

ただし、異なるジェネリックパラメータを持つ同じジェネリックに基づいて構築されたオブジェクトでGetType()を呼び出すと、2つの異なる型が返されます。 AとBは両方のクラスであり、RefTypeは一般的なものである場合:

RefType<A> a = new RefType<A>(); 
RefType<B> b = new RefType<B>(); 
Console.WriteLine("a type is "+a.GetType()); 
Console.WriteLine("b type is "+b.GetType()); 

結果に:

"a type is RefType`1[A]" 
"b type is RefType`1[B]" 

これはCLRの場合でも、そこにさまざまな構築型の型オブジェクトの作成を扱うことを意味しています「本当の」特別なインスタンス化はありませんか? CLRによって生成されたものと生成されなかったものを直接見る方法はありますか?

+0

*タイプ*は依然として非常に異なっています。テキストが言っていること(より明確なやり方でできていて、そこには多くの悪い書き方があります)は、これらの型を実装するために使用される実際のコードを参照型とのすべてのインスタンス化で共有できるということです。これは実装の詳細であり、通常はプログラマーにとってはほとんど問題ではありません。デバッガを接続し、これを見るにはコードをチェックする必要があります。私は、C#レベルでこれを確認する方法がないかどうかはわかりません。 –

答えて

2

これは、実際の特殊化されたインスタンス化がない場合でも、CLRが異なる構築型の型オブジェクトの作成を処理することを意味しますか?

はい。実行時の型チェックが言語の重要な部分であると考えてください。

var x = new List<string>() as List<object>; 

これはnullxを初期化することになっています。 new List<string>()の実行時の型情報が何らかの形でジェネリック型のパラメータを失ってしまった場合、これは機能しませんでした。

CLRによって生成されたものと生成されなかったものを直接見る方法はありますか?

class G<T> { public void f() { } } 
class A { } 
class B { } 
struct C { } 
struct D { } 
enum E : int { } 

static void Main(string[] args) 
{ 
    Console.WriteLine(typeof(G<object>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<string>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<A>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<B>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<C>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<D>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<E>).GetMethod("f").MethodHandle.Value); 
    Console.WriteLine(typeof(G<int>).GetMethod("f").MethodHandle.Value); 
} 

あなたはG<object>.fG<string>.fG<A>.fG<B>.fは、同じ方法でハンドルを持っていますが、G<C>.fG<D>.fG<E>.fG<int>.f全てが異なるものを持っていることがわかります。 G<E>.fG<int>.fも実装を共有していません。

+0

完全性(あるいは読者の練習問題)のために、 'G 'はその実装を他の参照型と共有するのに対し、 'G 'は参照型でもG でも実装を共有します。 –

+0

@ JeroenMostert提案をいただき、ありがとうございました。 – hvd

-1

Typeオブジェクトは抽象度の高い型情報を提供し、型が論理的にどのようなものかを伝えますが、ジェネリックの実装は低レベルの詳細なので頼りにはならないものです。実装の詳細はいつでも変更できます。

T<A>およびT<B>は、2つの異なるタイプであるため、異なるTypeオブジェクトで記述する必要があります。これは、Typeオブジェクトが、T<>の情報だけでなく、AまたはBの情報、つまりジェネリック型パラメータの情報を生成するためです。 2つのタイプが同じコードベースを共有しているという事実は違いはありません。

TypeオブジェクトはAPIに属します。この情報はコード内で使用できます。 Typeクラスは将来、言語の新機能を反映するために拡張される可能性がありますが、これは大きな変更ではありません。

効率的なコードを記述したい場合は、実装の詳細を知っておくとよいでしょう。いくつかの低レベルツール(O/Rマッパー、コードウィーバーなど)。ただし、実装の詳細に依存することがあります。

+0

便利なアドバイスですが、質問に対する答えはありません。場合によっては、実装の詳細を掘り下げたい場合もあります。 –

関連する問題