Будь-який метод може бути замінений (= virtual
) чи ні. Рішення приймає той, хто визначає метод:
class Person
{
public String GetPersonType()
{
return "person";
}
public virtual String GetName()
{
return "generic name";
}
}
Тепер ви можете замінити ті методи, які можна замінити:
class Friend : Person
{
public Friend() : this("generic name") { }
public Friend(String name)
{
this._name = name;
}
public override String GetName()
{
return _name;
}
}
Але ви не можете замінити GetPersonType
метод, оскільки він не віртуальний.
Давайте створимо два екземпляри цих класів:
Person person = new Person();
Friend friend = new Friend("Onotole");
Коли невіртуальний метод GetPersonType
викликається Fiend
екземпляром, насправді Person.GetPersonType
він називається:
Console.WriteLine(friend.GetPersonType());
Коли віртуальний метод GetName
викликається Friend
екземпляром, він Friend.GetName
називається:
Console.WriteLine(friend.GetName());
Коли віртуальний метод GetName
викликається Person
екземпляром, він Person.GetName
називається:
Console.WriteLine(person.GetName());
Коли невіртуальний метод називається, тіло методу не шукається - компілятор вже знає фактичний метод, який потрібно викликати. Тоді як у компіляторі віртуальних методів не може бути впевненого, який із них викликати, і він переглядається під час виконання в ієрархії класів знизу вгору, починаючи з типу екземпляра, до якого викликається метод: friend.GetName
він виглядає, починаючи з Friend
класу і знаходить це відразу, для person.GetName
класу це починається зPerson
і знаходить там.
Іноді ви робите підклас, перевизначаєте віртуальний метод і не хочете більше ніяких перевизначень в ієрархії - sealed override
для цього (кажучи, що ви останній, який замінює метод):
class Mike : Friend
{
public sealed override String GetName()
{
return "Mike";
}
}
Але іноді ваш друг Майк вирішує змінити стать і, отже, ім’я на Аліса :) Ви можете або змінити оригінальний код, або замість цього підклас Майк:
class Alice : Mike
{
public new String GetName()
{
return "Alice";
}
}
Тут ви створюєте зовсім інший метод з однаковою назвою (тепер у вас два). Який метод і коли викликається? Це залежить від того, як ви це називаєте:
Alice alice = new Alice();
Console.WriteLine(alice.GetName());
Console.WriteLine(((Mike)alice).GetName());
Коли ви телефонуєте з Alice
точки зору, ви телефонуєте Alice.GetName
, коли з Mike
телефону - дзвоните Mike.GetName
. Тут не виконується пошук під час виконання - оскільки обидва методи невіртуальні.
Ви завжди можете створити new
методи - віртуальні чи ні, які ви приховуєте.
Це стосується і властивостей, і подій - вони представлені як методи внизу.