Компиляция и приведение во время выполнения c # - PullRequest
17 голосов
/ 21 декабря 2010

Мне было интересно, почему некоторые приведения в C # проверяются во время компиляции, тогда как в других случаях ответственность снимается с CLR. Как и выше, оба неверны, но обрабатываются по-разному.

class Base { }
class Derived : Base { }
class Other { }

static void Main(string[] args)
{
    Derived d = (Derived)new Base();     //Runtime       InvalidCastException
    Derived d = (Derived)new Other();    //Compile-time  Cannot convert type...
}

Читая "C # в глубине" Я нашел информацию по этой теме, где автор говорит:
"Если компилятор обнаружит, что на самом деле это преобразование не работает, он вызовет ошибку компиляции - и если это теоретически разрешено, но фактически неверно во время выполнения, CLR выдаст исключение."

Означает ли "теоретически" связанный с иерархией наследования (какая-то другая близость между объектами?), Или это внутреннее дело компилятора?

Ответы [ 2 ]

22 голосов
/ 21 декабря 2010
  • Обновления могут быть проверены во время компиляции - система типов гарантирует, что приведение выполнено успешно.
  • Невозможно (вообще) проверить рейтинги во время компиляции, поэтому они всегда проверяются во время выполнения.
  • Несвязанные типы нельзя приводить друг к другу.

Компилятор рассматривает только статические типы.Среда выполнения проверяет динамический (во время выполнения) тип.Глядя на ваши примеры:

Other x = new Other();
Derived d = (Derived)x; 

Статический тип x равен Other.Это не связано с Derived, поэтому приведение не выполняется во время компиляции.

Base x = new Base();
Derived d = (Derived)x; 

Статический тип x теперь Base.Что-то типа Base может иметь динамический тип Derived, так что это уныло.В общем случае компилятор не может знать из статического типа x, является ли он типом времени выполнения Base, Derived, какого-либо другого подкласса Base.Таким образом, решение о том, разрешено ли приведение, оставлено на усмотрение.

1 голос
/ 21 декабря 2010

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

Ваш образец прост - вы создаете новый класс и сразу его разыгрываете.Но что, если вы получите Base откуда-то еще, например, вызов некоторого метода?Компилятор просто не может «угадать», что должен вернуть ваш метод, и поэтому выбрасывает, а не выбрасывает ошибку.

Когда вы приводите Other, компилятор видит, что нет никакой возможности, что Other на самом деле Derived и выдает исключение.

...