Будь-який метод може бути замінений (= 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методи - віртуальні чи ні, які ви приховуєте.
Це стосується і властивостей, і подій - вони представлені як методи внизу.