Написание выражений Upcasting и Downcasting в С#

Недавно я изучал повышение и понижение приведения в С#. Я понимаю, что повышение уровня относится к преобразованию из производного класса в базовый класс. Однако, когда я вижу практический пример повышения приведения (как показано ниже), я запутался.

public class Shape 
{
...
}

public class Circle : Shape
{
...
}

Circle circle = new Circle();
Shape shape = new Shape();
// Converting an object into its base class reference
shape = circle

Если мы преобразуем круг в ссылку на его базовый класс, не должно ли это быть похоже на

circle = shape 

Извините, если это звучит слишком любительски. Это потому, что я всегда видел выражения в следующем формате:

int x = 3; // means assign 3 to variable x. 

Так что я просто смущен, почему круг находится справа, а не слева. Пожалуйста, порекомендуйте. Считайте меня новичком.


person Farhan    schedule 24.10.2018    source источник


Ответы (6)


(Кроме того, это называется восходящим преобразованием, потому что традиционно диаграммы классов рисуются таким образом, что базовые классы физически отображаются над производными классами.)

Теперь, когда вы делаете:

shape = circle; // shape->(instance of Circle)

вы назначаете ссылку Circle ссылке Shape, так что после присвоения ссылка shape будет ссылаться на Circle.

Это нормально, потому что все, что можно сделать с Shape, можно сделать и с Circle.

Однако, если вы:

circle = shape; // circle->(instance of Shape)

вы назначаете ссылку Shape ссылке Circle. Вы не можете этого сделать, потому что (если бы это было возможно) вы могли бы получить доступ к Circle функциям, которых нет в Shape.

Например, представьте, что Circle.Radius существует, а Shape.Radius нет.

Если бы вам разрешили указать ссылку circle на Shape, что бы произошло, если бы вы попытались получить доступ к circle.Radius? Ответ будет таким: произойдет неопределенное поведение, потому что Shape.Radius не существует.

person Matthew Watson    schedule 24.10.2018

No

Проблема в том, что Shape — это не Circle, а Circle — это Shape.

Это означает, что Circle всегда можно поставить в то место, где требуется Shape, но когда вам нужен Circle, вы не можете поставить на его место Shape, так как это может быть и Triangle.

Вот почему вам нужно явно указать его (используя либо (Type)variable, либо variable as Type).

По существу, давайте предположим следующее:

class Shape {}
class Circle : Shape {}
class Triangle : Shape {}

Теперь у нас также есть Triangle, позволяющий нам на самом деле сделать это лучше:

Circle c = new Circle();
Triangle t = c; // Impossible due to Circle not being a Triangle
Shape s = c; // Possible because a Circle is a Shape
Triangle t2 = s; // Impossible because Shape may be a Triangle or any other derived class
person X39    schedule 24.10.2018

То, что вы в основном делаете в своем примере, также можно записать следующим образом:

Circle circle = new Circle();
Shape shape = (Shape)circle; //Casting the object to the base type

Итак, вы переводите свой объект типа Circle в объект типа Shape. В вашем коде это делается «автоматически», потому что вы присваиваете значение новой переменной типа Shape.

Это немного больше объясняет приведение/базовые классы: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions

person RedFox    schedule 24.10.2018

если вы знаете о наборе, вы можете легко понять, почему «форма = круг» может, а «круг = форма» не может.

думать об этом.

А — буква алфавита.

поэтому мы можем сказать

public class A : Alphabet
{
}

как мы знаем.

также Алфавит

public class Alphabet
{
}

если начертить схему то может быть так

┌───────── Alphabet ───────┐
│ A B C D E ... a b c ... z│
└──────────────────────────┘

Мы можем сказать, что z — это Alphabet, но мы не можем сказать, что Alplabet — это z, потому что Alphabet содержит больше, чем z.

Итак, давайте посмотрим на круг и форму.

Круг содержит информацию о форме и было добавлено больше переменных. (Возможно, это не так, но можно изменить.)

Таким образом, мы можем сказать, что Круг — это набор Формы.

Мы можем изменить Circle, который основан на Shape. Также мы можем инициализировать Circle.

но если вы сделаете «Форма = Круг», некоторые вещи, находящиеся в Круге, не могут быть инициализированы.

и он возвращает ошибку.

person Arphile    schedule 24.10.2018

попробую объяснить:

Переменная shape содержит ссылку на объект типа Shape.

Когда вы пишете Shape shape = new Shape();, переменная shape будет содержать ссылку на новый объект Shape.

Когда вы переназначаете shape, записывая shape = circle, он содержит ссылку на другой объект. Объект circle относится к типу circle, но поскольку круг наследует shape, это назначение можно выполнить; существует неявное приведение типа circle к типу Shape.

Другой и, возможно, более понятный способ сделать это приведение — сделать явное приведение:

Circle circle = new Circle();
Shape circleAsShape = (Shape)circle;
person mortb    schedule 24.10.2018

Преобразование означает изменение типа объекта на менее производный базовый класс (объект Circle на Sape).

Downcasting работает в другом направлении, например. литье с Shape на Circle.

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

В противном случае это не работает, так как Shape является общим, и мы не знаем, является ли это Circle. Таким образом, когда вы пытаетесь выполнить понижающее приведение, вам нужно указать это явно:

// this won't work
Shape shape = new Shape();
Circle c = (Circle)shape;
// this will
Shape shape = new Circle();
// we know we have Circle object so we can downcast
Circle c = (Circle)shape;
person Michał Turczyn    schedule 24.10.2018