すべてのスタンドアロンヒープオブジェクトはObject、から継承します。すべてのスタンドアロンヒープオブジェクトには、タイプを識別する手段など、特定の共通の側面が必要であるため、これは理にかなっています。そうでなければ、ガベージコレクターが不明なタイプのヒープオブジェクトへの参照を持っている場合、そのオブジェクトに関連付けられたメモリのBLOB内のどのビットが他のヒープオブジェクトへの参照と見なされるべきかを知る方法がありません。
さらに、型システム内では、構造のメンバーとクラスのメンバーを定義するために同じメカニズムを使用すると便利です。値型の格納場所(変数、パラメーター、フィールド、配列スロットなど)の動作は、クラス型の格納場所の動作とは非常に異なりますが、そのような動作の違いは、ソースコードコンパイラーと実行エンジン(型システムで表現されるのではなく、JITコンパイラ)。
この結果の1つは、値の型を定義すると、2つの型(ストレージロケーション型とヒープオブジェクト型)が効果的に定義されることです。前者は暗黙的に後者に変換され、後者は型キャストによって前者に変換されます。両方のタイプの変換は、問題のタイプの1つのインスタンスから別のインスタンスにすべてのパブリックフィールドとプライベートフィールドをコピーすることにより機能します。さらに、汎用制約を使用して、値型の保存場所のインターフェイスメンバを最初にコピーせずに直接呼び出すことができます。
値型ヒープオブジェクトへの参照はクラス参照のように動作し、値型のようには動作しないため、これはすべて重要です。たとえば、次のコードを考えてみましょう。
string testEnumerator <T>(T it)ここで、T:IEnumerator <string>
{
var it2 = it;
it.MoveNext();
it2.MoveNext();
それを返します。
}
public void test()
{
var theList = new List <string>();
theList.Add( "Fred");
theList.Add( "George");
theList.Add( "Percy");
theList.Add( "Molly");
theList.Add( "Ron");
var enum1 = theList.GetEnumerator();
IEnumerator <string> enum2 = enum1;
Debug.Print(testEnumerator(enum1));
Debug.Print(testEnumerator(enum1));
Debug.Print(testEnumerator(enum2));
Debug.Print(testEnumerator(enum2));
}
場合testEnumerator()メソッドが値型のストレージロケーションを渡され、itそのパブリック及びプライベートフィールド、渡された値からコピーされたインスタンスを受信します。ローカル変数it2は、フィールドがすべてからコピーされる別のインスタンスを保持しますit。を呼び出しMoveNextてit2も影響はありませんit。
上記のコードにクラスタイプの格納場所が渡されると、渡された値it、およびit2がすべて同じオブジェクトを参照するため、MoveNext()それらのいずれかを呼び出すと、それらすべてに対して効果的に呼び出されます。
キャストList<String>.EnumeratorするIEnumerator<String>と、値型からクラス型に効果的に変わることに注意してください。ヒープオブジェクトのタイプはList<String>.Enumerator異なりますが、その動作は同じ名前の値タイプとは大きく異なります。
object、それはのようなすべてのオブジェクト間でいくつかの基本的な機能、提供するため、一部では、.NETフレームワークの中でToString()とGetHashCode()