Что такое ссылка CLR и как она содержит информацию о типе? - PullRequest
4 голосов
/ 08 ноября 2010

Этим утром в моем мозгу произошла ошибка, пытавшаяся точно понять, как и когда C # может определить тип объекта по ссылке на этот объект. Рассмотрим следующий крайне неоригинальный пример кода:

class Foo { public virtual void Baz() { } }
class Bar : Foo { }

class Program {
    static void Main() {
        Foo f = new Bar();
        f.Baz();
    }
}

Тип ссылки там - Foo, но фактически созданный экземпляр объекта является Bar. Этот экземпляр Bar имеет некоторые издержки, то есть индекс блока синхронизации и ссылку на MethodTable, предположительно MethodTable Бара. Если вы посмотрите на объект Bar в куче, единственная подсказка к его типу - это ссылка на MethodTable, которая предполагает, что это Bar.

Тогда к вопросу. Есть ли способ для C # узнать из фактического графа объекта, что 'f' является Foo, и если да, то как? Содержит ли ссылка 'f' информацию о типе? Когда я вызываю f.Baz (), правильно ли я думаю, что отправка происходит через MethodTable Бара? Это просто тот случай, когда компилятор C # использует анализ потока, чтобы выяснить, что происходит и предотвратить любые незаконные операции? Неужели CLR на самом деле не заботится об объявлении типа Foo ко времени его преобразования в IL?

Извинения, если это скучный и плохо сформулированный вопрос - дайте мне знать, если требуется какое-либо разъяснение!

TL; DR - Как работает полиморфная ссылка в CLR? Как сохраняется какое-либо расхождение между фактическим и объявленным типом класса, и не могли бы вы сказать, какое исходное объявление было у результирующего IL?

Ответы [ 2 ]

5 голосов
/ 08 ноября 2010

Вы думаете, что это слишком сложно.

Содержит ли ссылка 'f' информацию о типе?

Нет.Это не обязательно.Это просто адрес начала памяти объекта Bar, который был построен ранее. Этот объект содержит таблицу виртуальных методов (и, возможно, ссылку на связанный с ним Type объект 1 , но здесь это не имеет значения).

Когда яВызовите f.Baz (), правильно ли я думаю, что отправка происходит через MethodTable Бара?

Да.

Это просто тот случай, когда компилятор C #использует анализ потока, чтобы выяснить, что происходит и предотвратить любые незаконные операции?

Анализ потока здесь сложен и совершенно не нужен.Компилятор разрешает именно те операции, которые разрешены для типа объявления f - Foo.Компилятор не заботится о фактическом (= динамическом) типе f.

Не могли бы вы сказать, какое исходное объявление было получено из результирующего IL?

Зависит. объект не не имеет статического типа, поэтому «указывать свой статический тип во время выполнения» не имеет смысла.Декларации, с другой стороны, отличаются.Если переменная является формальным параметром метода, тогда, конечно, вы можете (во время выполнения) использовать отражение, чтобы определить тип объявления параметра метода.

Для локальных переменных, снова эта операция не имеет смысла.С другой стороны, IL сохраняет эту информацию (как метаданные?) Через .locals, поэтому код может теоретически быть реверсивно спроектирован (Cecil и Reflector делают это), чтобы получитьстатический тип переменных.


1 Я предполагаю здесь, но это на самом деле невероятно .Если бы каждый объект содержал свою собственную ссылку на связанный объект Type, это означало бы дополнительные издержки указателя.Кроме того, эта ссылка совершенно не нужна, поскольку объект может просто вызвать GetType для получения своего типа.GetType должен быть реализован только один раз для каждого класса (на самом деле это статический метод) и отправляется через обычную таблицу виртуальных функций.Таким образом, для каждого класса требуется только одна ссылка на Type, в отличие от каждого объекта.

1 голос
/ 08 ноября 2010

Есть ли способ для C # узнать из фактического графа объектов, что 'f' - это Foo

, который статически известен компилятору

Содержит ли ссылка 'f' саму информацию о типе?

Интересно, она должна каким-то образом содержаться в IL.

Когда я вызываю f.Baz (),Правильно ли я считаю, что отправка происходит через MethodTable Бара?

Да.И это находится через экземпляр, на который указывает f.

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