Ошибка приведения типа и конструктор - PullRequest
0 голосов
/ 06 сентября 2010

У меня есть два класса

 public class A
    {
        public A()
        {

        }
    }

    public class B:A
    {
        public B()
        {

        }
    }

и это код в Main выглядит следующим образом

    A oa = new B();
    B ob = new A();

Здесь строка 1 успешно компилируется, а строка 2 отображает ошибку при типизации. Почему это происходит? Что именно происходит, когда вызывается new B() и new A()?

Ответы [ 2 ]

7 голосов
/ 06 сентября 2010

Вы объявили переменную типа B, а затем попытались присвоить ей значение типа A.Вы определили B как разновидность A, но это не значит, что все A являются B.

Думайте об этом так:

class Animal { }
class Dog : Animal { }
class Cat : Animal { }

Вы можете сделать Animal rex = new Dog(), потому что все собаки - животные, но не Dog fido = new Animal(), потому что не все животные - собаки.

2 голосов
/ 06 сентября 2010

Что именно происходит, когда новые B () и вызывается новый A ()?

  • new A() создает объект типа A в куче и возвращает ссылку на него.

  • new B() создает объект типа B в куче и возвращает ссылку на него.

Здесь строка 1 успешно компилируется в то время как строка 2 отображает приведение типов ошибка. Почему это происходит.

Так как B подклассы A, для ссылки типа A допустима ссылка на объект типа времени выполнения B. В конце концов, B - это просто «особый случай» A.

Однако обратное неверно, поскольку не все A с можно считать B с. Хотя это строго соблюдается системой типов * C safe , даже если нет «реальной» несовместимости, причины таких ограничений естественны. Представьте, например, что B объявил свойство public int Foo {get; set;}. Как вы ожидаете, что это будет вести себя:

B ob = new A();
ob.Foo = 5;

Это явно нелогично: объект real , на который ссылается ссылка, не имеет такого свойства. Следовательно, компилятор запрещает такие конструкции.

Теперь представьте, что вы изменили свой код на:

B b = (B)new A();

Здесь вы сообщаете компилятору, что созданный объект будет во время выполнения назначаться ссылке типа B. Это будет хорошо скомпилировано, но поскольку утверждение явно неверно, будет выброшено время выполнения InvalidCastException.

Подводя итог, можно сказать, что система типов C # (если вы игнорируете dynamic и несколько особых случаев) одновременно static и safe : вы не сможете успешно обработать бетон экземпляр A, как если бы он был типа B.

...