Вопросы, касающиеся приведения типа ссылки на объект в C #? - PullRequest
4 голосов
/ 03 ноября 2010

У меня есть вопрос относительно приведения типа объекта.Предположим, у нас есть:

A a = new A();
Object o = a;

Как я знаю, после этого компилятор скопирует адрес a и сохранит его в области памяти переменной o.Затем мы можем сказать, что a и o ссылаются на один и тот же объект.

Если мы сделаем что-то подобное:

String s = "abc";
int a = (int)s;

Тогда я понимаю, что компилятор не может скопировать строковое значение вобласть памяти int.

Но если у нас есть:

A a = new A();
B b = (B)a;

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

Итак, я не понимаю, что на самом деле происходит в памяти, из-за которой приведенное выше приведение не может быть выполнено.Это просто копирование адреса a в область памяти b?Если так, то почему это невозможно?Или он скопирует всех членов A, чтобы заменить всех членов B?

Спасибо

Ответы [ 2 ]

6 голосов
/ 03 ноября 2010

Компилятор Проверка статического типа означает, что если A и B не принадлежат к одной и той же иерархии наследования, это не позволит выполнить приведение между ними.

Подумайте об этом, если они не принадлежат к одной и той же иерархии, даже если компилятор позволяет вам привести объект A к типу B, поскольку A не наследует от B или его наследников, вы можете вызвать один из методов типа B на брошенном объекте, и он с треском провалится во время выполнения.

class A { }
class B { 
    void Foo() { }
}

A a = new A();
B b = (B)a;      // Compiler Error

// Hypothetically, if above was allowed, the below would ALWAYS fail at runtime
// Since there is no way the object "b" can handle this call.
b.Foo();


Здесь есть интересный момент, хотя, если B является интерфейсом, компилятор разрешил бы приведение, даже если они не принадлежат одному и тому же дереву наследования:

class A { }
interface B { 
    void Foo();
}

A a = new A();
B b = (B)a;      // Compiler lets this happens 

// Even though A does not implement B, but still one of the base classes of A 
// might have implement B and A inherits that so it might be able to handle this
b.Foo();

Причина этого в том, что A может быть из другого дерева иерархии, но все еще возможно, что A или один из его базовых классов реализовали B, так что у вас может быть точка этого преобразования, и компилятор позволит это.

0 голосов
/ 03 ноября 2010

Как объяснил Мортеза, компилятор C # будет выполнять статическую проверку типов, чтобы определить, возможно ли приведение.

Что касается того, что происходит во время выполнения, вы можете взглянуть на сгенерированный IL, чтобы получитьлучшая идея.Для ссылочных типов ваше приведение, вероятно, станет инструкцией IL castclass.Это приводит к тому, что во время выполнения проверяется фактический тип объекта, чтобы узнать, является ли приведение действительным.Если да, ссылка (32-битный или 64-битный указатель на ваш объект) подразумевается, что вы копируете в присваивании переменной, как вы и ожидали.Если нет, генерируется исключение InvalidCastException.

Для объектов ссылочного типа отдельные элементы никогда не копируются.Копируется только 32/64-битная ссылка.Для объектов типа значения отдельные элементы (поля) копируются во время присвоения.

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