Почему в этом случае выведется на экран "A"?
interface IPrinter
{
void Print();
}
public class A : IPrinter
{
public void Print()
{
Console.WriteLine("A");
}
}
public class B : A
{
public new virtual void Print()
{
Console.WriteLine("B");
}
}
public class C : B
{
public override void Print()
{
Console.WriteLine("C");
}
}
public class D : C
{
public override void Print()
{
Console.WriteLine("D");
}
}
internal class Program
{
public static void Main(string[] args)
{
IPrinter printer = new D();
printer.Print();
}
}
new virtual ничего специально не значит, это просто два модификатора, указанные вместе.
Попробуем разобраться, что происходит в коде.
interface IPrinter
{
void Print();
}
public class A : IPrinter
{
public void Print()
{
Console.WriteLine("A");
}
}
Метод A.Print становится реализацией объявления IPrinter.Print, поскольку у него то же имя, те же параметры, и тот же тип возвращаемого значения (void).
Теперь, когда мы приводим объект класса A к типу IPrinter и вызываем Print на самом деле будет вызван A.Print. Этот механизм работает похоже на переопределение виртуальных функций, но он немного сложнее.
Обратите внимание, что поскольку метод A.Print не объявлен как виртуальный, его нельзя переопределить. Его можно только заменить с помощью new.
public class B : A
{
public new virtual void Print()
{
Console.WriteLine("B");
}
}
Вот здесь метод Print уже объявлен виртуальным, его можно переопределять в наследниках. Но поскольку родительский метод не-виртуальный, мы должны использовать ключевое слово new, чтобы избавиться от предупреждения.
Что означает этот код? То, что поскольку метод A.Print не виртуальный, мы теряем информацию о конкретном типе при приведении к базовому типу.
var b = new B()
b.Print(); // B
var a = b as A;
a.Print(); // A <- B.Print() не переопределяет A.Print(), а заменяет его, поэтому так
Чтобы нужно сделать, чтобы вызов a.Print() печатал B, а не A?
public class A : IPrinter
{
public virtual void Print()
{
Console.WriteLine("A");
}
}
public class B : A
{
public override void Print()
{
Console.WriteLine("B");
}
}
Надо объявить метод виртуальным уже в классе A, а в B его переопределить.
В родительском IPrint классе метод Print не override, я уже точно не помню, но помоему чтобы его переопределить, override обязателен, но это не точно)
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости