Как именно работает Upcast в C#?
Из определения: Апкаст - приведение экземпляра производного класса к базовому
Фрагмент кода апкаста для примера. Класс Human производный от класса Mammal.
Human human = new Human();
Mammal mammal = (Mammal)human; //Upcast
- Если апкаст - это приведение экземпляра производного класса к базовому, то в данном случае экземпляр
humanклассаHumanдолжен был быть приведен к классуMammal. Но после этого фрагмента кода у экземпляраhumanсохраняются методы и переменные производного класса. В чем тогда выражается приведение к базовому классу? - Если апкаст - это создание нового экземпляра базового класса на основе экземпляра производного (в данном случае
mammalизhuman), то в чем разница между указанным выше кодом с апкастом и данным кодом:Human human = new Human; Mammal mammal = new Mammal();- ведь в итоге всё равно создается два экземпляра класса - производный и на основе его базовый?
P.S.: Я думаю, что мой вопрос не дублирует этот. Мой вопрос о технической стороне - почему апкаст был, а функционал остался как у производного класса.
Ответы (1 шт):
Автор решения: Igor Borzenkov
→ Ссылка
- Приведение типов никак не меняет содержимое объектов, т.е. при приведении не создаётся новых экземпляров классов.
- Вот здесь весьма подробно расписано в каких случаях необходимо использовать upcast. Но, пожалуй, в 95% случаев осуществлять явный upcast не имеет смысла. Компилятор C# весьма умный в этом отношении и приведение типов осуществляет неявным образом максимально комфортно для разработчиков.
Нижеприведенный пример демонстрирует базовые возможности объекта, приведенного к родительскому классу.
Обратите внимание на строчку mammal.AnyHumanMethod(); Она вызывает ошибку компиляции. C# является строго типизированным языком. Компилятор следит, чтобы обращения ко всем членам класса производилось именно у того типа, к которому приведен объект.
class Program
{
class Mammal
{
public virtual string Name => "It is a mammal";
}
class Human : Mammal
{
public override string Name => "It is a human";
public void AnyHumanMethod()
{
Console.WriteLine("Method was called");
}
}
static void Main()
{
var human = new Human();
Console.WriteLine(human.Name); // Будет выведено "It is a human"
human.AnyHumanMethod(); // Этот вызов корректен и допустим
var mammal = (Mammal)human;
// Сейчас всё равно будет вызван метод Human, т.к. несмотря на
// приведение, в переменной mammal хранится экземпляр класса Human
Console.WriteLine(mammal.Name); // Будет выведено "It is a human"
// У класса Mammal нет метода AnyHumanMethod, он есть только в классе Human
mammal.AnyHumanMethod(); // Ошибка компляции!
// Никакого создания нового объекта не происходит при приведение типов.
// Экземпляры классов human и mammal равны.
Console.WriteLine($"Сейчас будет возвращено значение True: {human == mammal}");
}
}