Усі автономні купи об’єкту успадковуються Object
; це має сенс, тому що всі самостійні об'єкти купи повинні мати певні спільні аспекти, наприклад, засіб визначення їх типу. В іншому випадку, якби у сміттєзбірнику було посилання на купі об'єкта невідомого типу, він би не міг дізнатися, які біти всередині блоку пам'яті, пов'язаного з цим об’єктом, слід вважати посиланням на інші об'єкти купи.
Крім того, всередині системи типів зручно використовувати один і той же механізм для визначення членів структур та членів класів. Поведінка місць зберігання типу значень (змінних, параметрів, полів, слотів масивів тощо) сильно відрізняється від поведінки місць зберігання типу класу, але такі поведінкові відмінності досягаються в компіляторах вихідного коду та механізмі виконання (в т.ч. компілятор JIT), а не виражається в системі типів.
Одним із наслідків цього є те, що визначення типу значення ефективно визначає два типи - тип місця зберігання та тип об'єкта купи. Перші можуть бути неявно перетворені в останні, а останні можуть бути перетворені в перші через typecast. Обидва типи перетворення працюють шляхом копіювання всіх публічних та приватних полів з одного примірника відповідного типу в інший. Крім того, можна використовувати загальні обмеження для виклику членів інтерфейсу безпосередньо у сховищі типу цінності, не створюючи попередньо його копії.
Все це важливо, тому що посилання на об'єкти типу значень типу поводяться як посилання класів, а не як типи значень. Розглянемо, наприклад, наступний код:
string testEnumerator <T> (T it) де T: IEnumerator <string>
{
var it2 = це;
it.MoveNext ();
it2.MoveNext ();
повернути його.Струм;
}
тест на публічну недійсність ()
{
var theList = новий Список <string> ();
theList.Add ("Фред");
theList.Add ("Джордж");
theList.Add ("Персі");
theList.Add ("Моллі");
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()