Подтвердить что ты не робот

Когда объект передается базовому классу, как он помнит, что это на самом деле?

Это новичок, но мне интересно узнать, что происходит здесь. Мой вопрос: что происходит за кулисами, когда вы бросаете объект? Поддерживает ли он какие-то метаданные о том, что изначально было? Вот что я имею в виду:

Предположим, что у меня есть метод под названием "ClockIn", который принимает параметр типа "Сотрудник":

public static void ClockIn(Employee employee)
{
   var manager = employee as Manager;
   if (manager != null)
   {
      manager.OpenSafe();
   }
}

Итак, предположим, что Manager является подклассом типа Employee и что он имеет метод OpenSafe:

public class Manager : Employee 
{
   public void OpenSafe()
   { 
      ... 
   }
}

Метод "ClockIn", если он обнаруживает, что диспетчер был передан, вызывает метод OpenSafe. Например:

var bob = new Manager();
ClockIn(bob);

Здесь я передал экземпляр типа Manager в метод, который принимает базовый класс Employee. Мне нужно передать экземпляр внутри метода ClockIn в диспетчер, прежде чем я могу позвонить OpenSafe.

Вопрос в том, есть ли какие-то метаданные, которые помнят, что "bob" - это Менеджер, хотя я передал его как Employee? Как код знает, что он действительно может быть передан менеджеру? Что-то происходит в куче?

4b9b3361

Ответ 1

Первое, что нужно помнить, это то, что кастинг вообще не изменяет исходный объект. Это только изменяет ваш взгляд на объект через эту конкретную ссылку. Более чем одна ссылка может указывать на один и тот же объект, поэтому изменение объекта не является разумной задачей при создании.

Что вы можете сделать в своем примере - сделать ClockIn() метод класса Employee. Затем, когда вы вызываете

bob.ClockIn();

то bob будет знать, какой тип он есть на самом деле, и назовите соответствующий метод ClockIn() для его типа. Это называется динамическая отправка метода и недоступна для функций static, как в вашем примере.

Например:

public class Employee {
    public void ClockIn() {
        ....
    }
}

public class Manager: Employee {
    public void ClockIn() {
        // first, do what all Employees do when clocking in
        Employee.ClockIn();
        // Next, do Manager specific actions
        OpenSafe();
    }
    public void OpenSafe() {
        ....
    }
}

Ответ 2

Casts не меняет тип среды выполнения объекта.

Вызов метода GetType возвращает объект Type, представляющий его тип выполнения.

Ответ 3

Кастинг не влияет на объект - он влияет на ссылку на объект.

Все, что вы делаете, когда вы опускаете объект, сообщает компилятору, что на этот объект может ссылаться переменная, которая происходит от типа, который в данный момент ссылается на объект.

Ключевым моментом является то, что класс объекта никогда не изменяется, вы только меняете тип ссылки на объект.

Ответ 4

Фактический тип объекта всегда сохраняется как ссылка на его System.Type. На самом деле у каждого объекта .NET есть дополнительное поле System.Type, ссылающееся на его фактический тип.

Ответ 5

Расширяя приведенные выше ответы, полезно подумать об общественных аспектах класса как о электрической панели. Фиксированные внешние точки подключения подключаются к внутренней работе класса. Если класс наследует другой класс, объекты нового класса получают панель, помеченную их новым типом класса, в дополнение к панели типа базового класса. Добавление интерфейса добавляет еще одну панель.

Если свойство или метод объявлены переопределяемыми, на задней панели панели "соединение" для этого метода/свойства будет предусмотрен съемный штекер; иначе это не будет. Предположим, что класс "Alpha" имеет переопределяемый метод "foo" и неперекрываемую функцию "bar". Производный класс "Браво" переопределяет "foo" и "bar" теней. Объекты класса "Браво" будут иметь как "Alpha.foo", так и "Bravo.foo", подключенные к функции Bravo "foo" ; они будут иметь "Alpha.Bar", подключенный к функции "Бар" Alpha, а "Bravo.Bar" подключен к функции "Bar" Браво.

Если объект "BravoInstance" типа "Браво" используется где-то там, где ожидается "Браво" , ссылка на его "BravoInstance.Bar" заставит систему посмотреть панель объекта "Браво" и использовать ее Соединение "Bar" (подключено к Bravo.Bar). Если такой экземпляр присваивается коду, который ожидает Alpha (вполне допустимый из-за наследования), попытка доступа к ToInStance.Bar будет подключаться к панели "Alpha" панели "Bar" (которая, в свою очередь, подключена к Alpha.Bar).

Временами затенение полезно и целесообразно, но нужно быть очень осторожным при затенении метода или свойства объекта, который может быть передан в код, который ожидает базовый тип.