Почему CIL поддерживает экземпляры, если он основан исключительно на стеке

В Common Intermediate Language (CIL) мы можем создавать экземпляры классов, которые не являются статическими. Это имеет смысл, если нам нужно хранить данные экземпляра между вызовами методов. Почему это необходимо в CIL, где все в любом случае находится в стеке? В CIL нет данных экземпляра, зачем мне экземпляр? Или виноват компилятор: почему компилятор не компилирует каждый метод статическим в CIL? Я предполагаю, что информацию о коде более высокого уровня можно извлечь из CIL. Это, вероятно, звучит глупо для опытного программиста CIL, потому что это может быть совершенно неправильно, но я только начинаю вникать в это.

Приветствуются любые разъяснения.


person Noel Widmer    schedule 14.10.2016    source источник


Ответы (2)


Неявное предположение в CIL состоит в том, что объекты класса хранятся в куче сборщика мусора. Точность также во время выполнения. При создании объекта вы получаете ссылку на объект. Указатель. Он занимает 4 байта в 32-битном режиме, 8 байтов в 64-битном режиме.

Что вы делаете с этим указателем, зависит от вашего кода. Вы можете сохранить его в локальной переменной (аналогично хранению в стеке) или вы можете сохранить его в поле или статической переменной. Во время выполнения он принципиально не отличается от IntPtr, за исключением того, что сборщик мусора всегда может найти его обратно. Это необходимо, когда он перемещает объект при сжатии кучи, значение указателя необходимо обновить. Под капотом происходит много волшебства, чтобы помочь GC найти этот указатель обратно, своевременный компилятор играет важную роль < / а>.

С точки зрения времени выполнения все методы статичны. Довольно заметно, когда вы пишете метод расширения. Между статическим методом C # и методом экземпляра отличается дополнительный скрытый аргумент, который передается методу. Вы это хорошо знаете, это this. Ключевое слово, которое вы всегда можете использовать в методе экземпляра. Вам не нужно называть его самостоятельно в списке параметров метода, компилятор позаботится об этом. Вы явно называете его в методе расширения.

person Hans Passant    schedule 14.10.2016

Одна из причин - виртуальные методы. CLR понимает виртуальные методы, и когда используется код операции callvirt, она вызывает правильное переопределение в зависимости от типа среды выполнения экземпляра.

Если бы все методы были статическими, это было бы невозможно. Компилятор C # (и любой другой компилятор) должен будет реализовать виртуальную диспетчеризацию самостоятельно, что также предотвратит различные оптимизации девиртуализации.

person svick    schedule 14.10.2016