#c_sharp #исключения #runtime
Тест на собеседовании Проходил онлайн-собеседование и был предложен тест: What is the result of the following code? int a = 5; object b = a; double c = (double)b; Console.Write(c); 5 compilation error Neither answer is correct run-time error (exception) Мой ответ На сколько я понял это тест на глубокое понимание внутренней "кухни" C#. И дал я на него не правильный ответ - 5. После всего я набрал данный пример и вот что получилось во время выполнения: Вопрос Компилятор ничего не подсветил. Почему так произошло? Что не может заранее увидеть компилятор, что может выявится во время run-time? Правильно ли я понял, что в строке object b = a; переменная b динамически получает ссылочный тип, а на строке double c = (double)b; мы пытаемся преобразовать ссылочный тип в значимый ((double)b) и поэтому выскакивает исключение?
Ответы
Ответ 1
Никакой особой «внутренней кухни» тут нет. Для начала, выражение object b = a;. Это упаковка. Согласно документации, упаковка всегда возможна и является неявным преобразованием. Поэтому компилятор не ругается на несоответствие типов, упаковка в object возможна всегда. Теперь, выражение double c = (double)b;. Тип b — object, поэтому это выражение является распаковкой в значимый тип double. Смысл распаковки такой: если в b в самом деле упаковано значение в точности типа double, то оно оттуда берётся, иначе происходит исключение. Компилятор не следит за тем, какой тип был ранее упакован в b (потому что в общем случае он не может этого сделать), так что он не знает, что в b реально int. Чего компилятор не делает, так это попытки достать int из b, и попытаться преобразовать его к double. Опять-таки потому, что он не умеет преобразовать во время выполнения произвольный значимый тип в другой значимый тип (а точный тип, лежащий в b, компилятор не знает). В вашем случае в b оказывается упакованный int, так что происходит «законное» исключение.Ответ 2
Boxing/Unboxing int a = 5; object b = a; В CLR существует такое понятие как boxing — это преобразование value-of типа в ссылочный тип. Когда вы выполняете неявное преобразование в System.Object в этом примере, CLR создаст объект в куче и присвоит его полю значение 5. Этот механизм существует по ряду причин, одна из которых, это утверждение что любой тип в CLR наследуется от System.Object double c = (double) b; Обратный процесс называется unboxing и одной из его особенностей является то, что упакованный тип должен быть распакован именно в тот тип, в который был упакован. В вашем примере, запакованный тип — Int32, значит именно в Int32 он и должен быть распакован. Если выполнить ваш пример и пропустить этап boxing/unboxing то всё было бы корректно: int a = 5; double c = (double) a; Если выполнить требования CLR и распаковать тип в нужный, то дальнейшее преобразование тривиально: int a = 5; object b = a; double c = (int) b;
Комментариев нет:
Отправить комментарий