Как делают на самом деле, кастинги работают на уровне CLR?

При выполнении восходящего или удрученного, что действительно происходит негласно? У меня была идея что при выполнении чего-то как:

string myString = "abc";
object myObject = myString;
string myStringBack = (string)myObject;

бросок в последней строке имел бы как, только цель говорит компилятору, что мы в безопасности, мы не делаем ничего плохого. Так, у меня была идея, что на самом деле никакой код кастинга не будет встроен в самом коде. Кажется, что я был неправ:

.maxstack 1
.locals init (
    [0] string myString,
    [1] object myObject,
    [2] string myStringBack)
L_0000: nop 
L_0001: ldstr "abc"
L_0006: stloc.0 
L_0007: ldloc.0 
L_0008: stloc.1 
L_0009: ldloc.1 
L_000a: castclass string
L_000f: stloc.2 
L_0010: ret 

Почему CLR нужно что-то как castclass string?

Существует две возможных реализации для удрученного:

  1. Вы требуете a castclass something. Когда Вы добираетесь до строки кода, которая делает castclass, CLR пытается сделать бросок. Но затем, что произошло бы, я опустил строковую строку castclass и попытался выполнить код?
  2. Вы не требуете a castclass. Поскольку все ссылочные типы имеют подобную внутреннюю структуру, при попытке использовать строку на экземпляре Формы, то это выдаст исключение неправильного использования (потому что это обнаруживает Форму, не строка или любой из ее подтипов).

Кроме того, следующий statamente от C# 4.0, вкратце исправляют?

Upcasting and downcasting between compatible reference types performs reference
conversions: a new reference is created that points to the same object.

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

Спасибо

6
задан devoured elysium 6 May 2010 в 18:38
поделиться

2 ответа

У меня была идея, что на самом деле код приведения не будет встроен в самом коде.

Интересная идея. Как вы себе представляли, что это работает?

try
{
    object x = 123;
    object y = (string)x;
}
catch(InvalidCastException ex)
{ ... }

Если привести не создает кода, то где происходит код, который выдает исключение?

Помните, что основная цель приведения от менее конкретного типа к более конкретному типу состоит в том, чтобы выполнить проверку типа среды выполнения.

Как только проверка типа пройдет, то, конечно, больше ничего не должно произойти. Биты ссылки перед проверкой типа и биты после проверки типа являются одними и теми же битами; мы только что проверили, что новое использование старых битов оправдано.

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

Где он это обнаруживает? Я имею в виду, в какая именно инструкция обнаружена? В инструкции по кастклассу. Вот для чего предназначена инструкция каст-класса.

Что было бы, если бы я опустил строковую строку castclass и попытался запустить код?

Верификатор безопасности типов отклонил бы вашу программу. Если бы вы заставили КЛR запустить его без прохождения проверки, то она имела бы неопределенное поведение. Возможно, это удалось, возможно, он потерпел неудачу, он мог отформатировать ваш жесткий диск.

Действительно ли это создает новую ссылку?

Помните, что на уровне реализации ссылка — это просто целое число размером с указатель. Это число, которое диспетчер памяти может использовать для отслеживания положения ссылающихся данных. Это может быть указатель, это может быть ручка, неважно, что это такое; это то, что реализует абстрактное понятие ссылки.

Когда у вас есть переменная, содержащая 12, и вы «заменяете» ее содержимое на 12, это «новая» 12, которая только что была создана, или это «старый» 12? Предположим, вы делаете вторую переменную и ставите в нее 12, копируя из первой переменной. Это «новые» 12 или «старые» 12? Как вы можете сказать? Это разница, которая не имеет никакого значения.Когда вы делаете «новую» ссылку, которая идентична «старой» ссылке, это создает что-то новое? Вопрос философский, а не технический.

14
ответ дан 8 December 2019 в 12:18
поделиться

Вы путаете ссылку с экземпляром. Создается новая ссылка , а не новый экземпляр.

object foo = "bar";
string baz = (string)foo;

Новая ссылка на строку «foo» назначается переменной baz (но по-прежнему существует только один экземпляр строки, это просто что обе переменные указывают на единственный экземпляр). Если бы это было не так, у вас было бы что-то вроде «ручки». Если бы baz и foo были буквально одной и той же ссылкой, то это ..

foo = "bim";

также сделало бы baz равным «bim» (аналогично, присвоение нестрокового типа приведет к тому, что baz больше не будет указывать на действительную строковую ссылку).

Вы можете выполнить приведение к ссылочному типу, если они находятся в одной и той же иерархии наследования (один наследуется от другого прямо или косвенно), или когда существует явное преобразование между типами. Обратите внимание, что явные преобразования, как и все другие операторы, не являются полиморфными - то есть преобразование должно быть определено специально для одного из рассматриваемых классов , а не в другой точке иерархии.

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

5
ответ дан 8 December 2019 в 12:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: