Динамическая отправка - шаблонный метод в C # - PullRequest
0 голосов
/ 30 января 2019

Я не понимаю, почему выводится следующий вывод.

Статический тип является базовым и вызывает print () и приводит к выводу на консоль:

  • Sub1.A
  • Base.B

Статический тип имеет значение Sub и вызывает print () и приводит к выводу на консоль:

  • Sub1.A
  • Base.B

Почему здесь вызывается Base.B, а не Sub.B?

Статическим типом является Sub, и вызов B () приводит к выводу консоли:

  • Sub1.B

В программе вызывается скрытая функция B () на Sub.Но нет, если я вызову это с помощью print ().

static void Main(string[] args)
{                
            Base b = new Sub();
            Sub s =  b as Sub;

            b.print(); //See first paragraph with 2 bullet points
            s.print(); //See second paragraph bullet points
            s.B(); //See third paragraph with bullet points

}

public class Base
{
        public Base() {}

        public void print()
        {
            A();
            B();
        }

        public virtual void A() { Console.WriteLine("Base.A"); }

        public void B() { Console.WriteLine("Base.B"); }
}

public class Sub : Base
{
        public Sub()  { }

        public override void A() { Console.WriteLine("Sub1.A"); }

        public new void B() { Console.WriteLine("Sub1.B"); }
}

1 Ответ

0 голосов
/ 30 января 2019

Разница заключается в том, как каждый метод вызывается из каждого места, и сводится к различиям между new и virtual / override.

Сначала теория, упрощенное объяснение обоихключевые слова:

  • new просто определяет другой метод в производном классе с тем же именем существующего метода в базовом классе, «скрывая» его.Выбор метода для вызова (базовый или производный) выполняется в время компиляции , в зависимости от типа ссылки, используемой для вызова метода.
  • virtual указывает, что методможет иметь альтернативную реализацию в производном классе, и в этом случае его следует использовать вместо этого.Здесь выбор делается в время выполнения в зависимости от типа реального объекта.

Теперь примените его к вашему случаю.Все вызовы A здесь абсолютно одинаковы, поскольку они виртуальны, и единственный находящийся экземпляр имеет тип Sub.Динамическая диспетчеризация делает свое дело, и это приводит к вызову на Sub.B, как вы нашли.

Но вызовы на B находятся в двух местах.Один внутри метода print, а другой непосредственно main.Поскольку B не virtual, он использует статическую диспетчеризацию и тип ссылки время компиляции для определения сайта вызова.Один из main достаточно прост, чтобы понять, почему он использует Sub.B.Другой в методе print, однако, не использует те же ссылки, он вызывает метод экземпляра в том же классе, неявно используя указатель this.Это полностью эквивалентно написанию этого:

public void print()
{
    this.A();
    this.B();
}

Так что вызов B полностью зависит от типа времени компиляции this, то есть Base в данном случае (как написано в этом классе).Поэтому здесь вызывается Base.B.

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

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