вниз и вверх

88

Я новичок в C #ООП ). Когда у меня есть такой код:

class Employee
{
    // some code
}


class Manager : Employee
{
    //some code
}

Вопрос 1 : Если у меня есть другой код, который делает это:

   Manager mgr = new Manager();
   Employee emp = (Employee)mgr;

Вот Employeeон Manager, но когда я его вот так Employeeпередаю, это означает, что я его повышаю?

Вопрос 2 :

Когда у меня есть несколько Employeeобъектов класса, и некоторые из них, но не все, являются объектами Manager, как я могу их уменьшить, где это возможно?

user184805
источник
6
Повышение частоты может быть выполнено без явного приведения. Так Employee emp= mgr;должно хватить.
поцелуй мою подмышку

Ответы:

93
  1. Это правильно. Когда вы это делаете, вы преобразуете его в employeeобъект, а это значит, что вы не можете получить доступ ни к чему конкретному менеджеру.

  2. При понижении качества вы берете базовый класс, а затем пытаетесь превратить его в более конкретный класс. Этого можно добиться с помощью is и явного приведения типа:

    if (employee is Manager)
    {
        Manager m = (Manager)employee;
        //do something with it
    }
    

или с таким asоператором:

Manager m = (employee as Manager);
if (m != null)
{
    //do something with it
}

Если что-то непонятно, буду рад исправить!

RCIX
источник
Мне нужен пример, чтобы узнать, что такое Downcasting?
user184805 06
4
Избегайте переопределения устоявшихся терминов: «упаковка» в контексте ООП и C # означает нечто совершенно иное (= перенос объекта типа значения в ссылку). Кроме того, в вашем примере можно (и нужно) использовать asоператор вместо is, за которым следует приведение.
Конрад Рудольф
2
Я исправился по первому пункту, и я изменил вторую половину своего ответа, чтобы показать оба способа сделать это.
RCIX
2
Ваше первое утверждение («... преобразование [экземпляра класса Manager] в объект« сотрудник »[..] означает, что вы не можете получить доступ к чему-либо, относящемуся к менеджеру») не совсем точен. В примере OP, если у Employee есть виртуальный член, который переопределен в Manager, CLR вызовет реализацию Manager, несмотря на приведение. Из статьи MSDN о полиморфизме в C #: «Когда производный класс переопределяет виртуальный член, этот член вызывается, даже если к экземпляру этого класса обращаются как к экземпляру базового класса». Пример, предоставленный MSDN, практически идентичен.
Энтони
49

Апкастинг (использование (Employee)someInstance) обычно прост, поскольку компилятор может сообщить вам во время компиляции, является ли тип производным от другого.

Однако обычно понижающее преобразование должно выполняться во время выполнения, поскольку компилятор не всегда может знать, относится ли рассматриваемый экземпляр к заданному типу. C # предоставляет для этого два оператора - is, который сообщает вам, работает ли понижающее преобразование, и возвращает true / false. И as which пытается выполнить приведение и возвращает правильный тип, если это возможно, или null, если нет.

Чтобы проверить, является ли сотрудник менеджером:

Employee m = new Manager();
Employee e = new Employee();

if(m is Manager) Console.WriteLine("m is a manager");
if(e is Manager) Console.WriteLine("e is a manager");

Вы также можете использовать это

Employee someEmployee = e  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (e) is a manager");

Employee someEmployee = m  as Manager;
    if(someEmployee  != null) Console.WriteLine("someEmployee (m) is a manager");
Прит Сангха
источник
11
  • Апкастинг - это операция, которая создает ссылку на базовый класс из ссылки на подкласс. (подкласс -> суперкласс) (т.е. менеджер -> сотрудник)
  • Понижающее преобразование - это операция, которая создает ссылку на подкласс из ссылки на базовый класс. (суперкласс -> подкласс) (т.е. Сотрудник -> Менеджер)

В твоем случае

Employee emp = (Employee)mgr; //mgr is Manager

вы делаете апкастинг.

Приведение вверх всегда успешно, в отличие от понижающего, которое требует явного приведения, поскольку оно потенциально может завершиться ошибкой во время выполнения ( InvalidCastException ).

C # предлагает два оператора, чтобы избежать генерации этого исключения:

Начиная с:

Employee e = new Employee();

Первый:

Manager m = e as Manager; // if downcast fails m is null; no exception thrown

Второй:

if (e is Manager){...} // the predicate is false if the downcast is not possible 

Предупреждение : когда вы выполняете апкастинг, вы можете получить доступ только к методам, свойствам суперкласса и т. Д.

победитель
источник
6

Если вам нужно проверить каждый объект Employee, является ли он объектом Manager, используйте метод OfType:

List<Employee> employees = new List<Employee>();

//Code to add some Employee or Manager objects..

var onlyManagers = employees.OfType<Manager>();

foreach (Manager m in onlyManagers) {
  // Do Manager specific thing..
}
ХОКБОНГ
источник
2

Ответ 1: Да, это называется апкастингом, но то, как вы это делаете, не современно. Повышение качества может выполняться неявно, вам не нужно никакого преобразования. Так что просто напишите Employee emp = mgr; достаточно для апкастинга.

Ответ 2: Если вы создаете объект класса Manager, мы можем сказать, что менеджер является сотрудником. Потому что класс Manager: Employee отображает отношения Is-A между классом Employee и классом Manager. Таким образом, можно сказать, что каждый менеджер - это сотрудник.

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

Итак, ответ таков: если вы хотите преобразовать объект класса Employee в объект класса диспетчера, сначала вы должны иметь объект класса диспетчера, затем вы можете его преобразовать, а затем вы можете уменьшить его.

Асад Патель
источник
-1

Повышение и понижение:

Повышение качества: приведение от производного класса к базовому классу. Приведение вниз: приведение от базового класса к производному классу

Разберем то же самое на примере:

Рассмотрим два класса Shape как родительский класс и Circle как производный класс, определенные следующим образом:

class Shape
{
    public int Width { get; set; }
    public int Height { get; set; }
}

class Circle : Shape
{
    public int Radius { get; set; }
    public bool FillColor { get; set; }
}

Апкастинг:

Форма s = новая форма ();

Круг c = s;

И c, и s ссылаются на одну и ту же ячейку памяти, но оба они имеют разные представления, т.е. используя ссылку «c», вы также можете получить доступ ко всем свойствам базового и производного классов, но используя ссылку «s», вы можете получить доступ к свойствам единственного родительского класса.

Практическим примером апкастинга является класс Stream, который является базовым классом для всех типов потокового считывателя фреймворка .net:

StreamReader reader = новый StreamReader (новый FileStreamReader ());

здесь FileStreamReader () преобразован в streadm reder.

Понижение:

Форма s = новый круг (); здесь, как объяснено выше, представление s является единственным родителем, чтобы сделать его и для родителя, и для ребенка, нам нужно его уменьшить

var c = (Круг) s;

Практическим примером Downcasting является класс кнопок WPF.

AutomationNerd
источник