Как ValueType.GetType () может определить тип структуры? - PullRequest
27 голосов
/ 29 мая 2009

Для ссылочного типа макет памяти объекта:

| Type Object pointer|
|    Sync Block      |
|  Instance fields...|

Для типа значения макет объекта выглядит как

|  Instance fields...|

Для ссылочного типа GetType означает найти объект из «Указателя типа объекта». Все объекты данного объекта ссылочного типа указывают на один и тот же тип объекта (который также имеет таблицу методов)

Для типа значения этот указатель недоступен. Так как же работает GetType ()?

Я проверил в Google и нашел этот фрагмент ... который немного туманный. Кто-нибудь может уточнить?

Решение состоит в том, что местоположение в какое значение хранится может хранить только значения определенного типа. Это гарантируется проверяющим. Источник

Ответы [ 2 ]

25 голосов
/ 29 мая 2009

Вызов GetType() для поля типа значения этого типа значения. Перемещая тип значения в кучу, вы получаете ссылочный тип, который теперь имеет указатель на тип этого объекта.

Если вы хотите избежать бокса, вы можете вызвать GetTypeCode, который возвращает перечисление, указывающее тип типа значения без его упаковки.

Вот пример, показывающий происходящий бокс:

C #:

class Program
{
    static void Main()
    {
        34.GetType();
    }
}

IL для Main():

.method private hidebysig static void Main() cil managed
{
        .entrypoint
        .maxstack 8
        L_0000: ldc.i4.s 0x22
        L_0002: box int32
        L_0007: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
        L_000c: pop 
        L_000d: ret 
}

Редактировать: Чтобы показать, что делает компилятор, давайте изменим тип литерала следующим образом:

class Program
{
    static void Main()
    {
        34L.GetType();
    }
}

Добавляя "L" после литерала, я сообщаю компилятору, что я хочу, чтобы этот литерал был преобразован в System.Int64. Компилятор видит это, и когда он выдает инструкцию box, он выглядит так:

.method private hidebysig static void Main() cil managed
{
        .entrypoint
        .maxstack 8
        L_0000: ldc.i4.s 0x22
        L_0002: conv.i8 
        L_0003: box int64
        L_0008: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
        L_000d: pop 
        L_000e: ret 
}

Как вы можете видеть, компилятор проделал тяжелую работу по определению правильных команд, которые должны быть отправлены, после этого он должен выполнить CLR.

5 голосов
/ 01 июня 2009

Возможно, Эндрю Х. воспринял это как очевидное и изо всех сил пытался заставить меня понять +1. момент моей лампочки пришел от Джона Скита ... снова (на этот раз через его книгу, которую я случайно прочитал ... и вокруг того региона, где лежали ответы.

  • C # является статически типизированным. Каждая переменная имеет тип и известна во время компиляции.
  • Типы значений не могут быть унаследованы. В результате объекты VT не должны переносить дополнительную информацию о типе (в отличие от объектов типа Ref, каждый из которых имеет заголовок типа объекта, поскольку тип переменной и значение / тип объекта может отличается.)

Рассмотрите фрагмент ниже. Хотя тип переменной - BaseRefType, он указывает на объект более специализированного типа. Для типов значений, поскольку наследование запрещено, тип переменной равен типу объекта.

BaseRefType r = new DerivedRefType(); 
ValueType v = new ValueType();

Моим недостающим элементом была пуля № 1.
<Snipped after J.Skeet's comment since it seems to be wrong>. Кажется, есть какая-то магия, которая позволяет компилятору / среде выполнения знать «тип переменной» для любой произвольной переменной. Поэтому среда выполнения каким-то образом знает, что ob имеет тип MyStruct, хотя сам объект VT не имеет информации о типе.

MyStruct ob = new MyStruct();
ob.WhoAmI();                          // no box ; defined in MyStruct
Console.WriteLine(ob.GetHashCode());  // no box ; overridden in ValueType
Console.WriteLine( ob.GetType() );    // box ; implemented in Object

Благодаря этому я могу вызывать методы, определенные в MyStruct (и по каким-то причинам ValueType), без привязки к RefType.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...