Почему явное преобразование требуется для назначения базового класса производному классу?Но не обязательно делать обратное - PullRequest
8 голосов
/ 16 декабря 2011

У меня есть базовый класс и производный класс, как показано ниже

public class animal
{
    public string name { get; set; }
}

public class dog : animal
{
    public int age { get; set; }
    public string type { get; set; }
}

использует:

animal a = new animal();

dog d = new dog();

a = d; //compiled

d = a; //Error:Cannot implicitly convert type 'animal' to 'dog'.

d = (dog)a; // compiled

Что происходит внутри, что производный класс может быть назначен базе, но выполняется обратное явное преобразованиенеобходимо?Обнаружен один и тот же результат, даже если базовый и производный класс содержат один и тот же член.

Ответы [ 5 ]

9 голосов
/ 16 декабря 2011

Все собаки - животные, но не все животные - собаки.Неявное преобразование недопустимо, потому что ваш a не может быть d.

6 голосов
/ 16 декабря 2011

Когда вы используете явное преобразование, в вашем случае вы сообщаете компилятору, что знаете, что происходит.Если вы скомпилируете свой код, удалив d = a;, и вы попытаетесь получить доступ к общедоступному члену на d, возникнет исключение.Это потому, что в данном случае animal не является dog.Вы явно создали animal и присвоили ему a.

Явное преобразование позволяет вам что-то делать, когда вы знаете преобразование будет работать.

public class MyClass
{
    public animal MyAnimal { get; private set; }

    public MyClass ()
    {
        MyAnimal = new dog ();
    }

    public void SetAge (int Age)
    {
        ((dog)MyAnimal).age = Age;
    }
}

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

Мы знаем, что когда класс наследует от своего базового класса, он берет с собой открытые свойстваи методы.Вы не можете сказать, что ваша ссылка на animal всегда будет содержать свойства и методы dog.

3 голосов
/ 16 декабря 2011

Это простое правило наследования.Например: Собака - это животное , но обратное неверно - Animal is Dog.Может быть количество подклассов Animal.

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

Animal a=new Cat(); // OK
a=new Dog(); // OK

Cat c=a; //Invalid - var a might contains reference of Cat or Dog
Cat d=(Cat)a; // Throws InvalidCastException exception because "a" has ref. of Dog

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

Посмотрите статью MSDN - Практическое руководство. Безопасное приведение с помощью операторов as и is (Руководство по программированию в C #).

2 голосов
/ 16 декабря 2011

Что происходит внутри, что производный класс может быть назначен базе, но требуется обратное явное преобразование? Обнаружен один и тот же результат, даже если базовый и производный класс содержат один и тот же член.

Почти ничего внутри не происходит, в любом случае. Объект не изменяется или не копируется; скорее просто ссылка на него сохраняется в новой переменной другого типа.

Неявное преобразование из dog в animal разрешено, потому что если переменная dog может содержать ссылку на объект, тогда объект должен быть dog или poodle или еще чем-то, поэтому Переменная animal также может содержать ссылку на нее.

В отличие от этого, требуется явное преобразование из animal в dog, поскольку объект animal в действительности не может быть dog, и в этом случае система времени выполнения вызовет исключение. (Помните, когда я сказал, что «почти ничего не происходит внутри»? Это « почти ничего», потому что система времени выполнения должна будет проверить, чтобы убедиться, что объект является dog, и поднять исключение в противном случае.)

Это решение по разработке языка & mdash; мы определенно могли бы создать язык, точно такой же, как C #, за исключением того, что dog d = a; эквивалентен dog d = (dog) a;, но разработчики C # (и многих похожих языков) чувствовали, что для dog d = a; было бы непонятно повышать время выполнения исключение иногда. Явное приведение проясняет, что исключение возможно, если a не ссылается на dog.

2 голосов
/ 16 декабря 2011

Подумайте об этом так, все собаки уже животные, но не все животные - собаки. Чтобы присвоить животное собаке, вы должны сначала преобразовать его в собаку.

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