Возможный дубликат:
Почему С# реализует методы как не виртуальные по умолчанию?
Я говорю в основном о С#,.NET 3.5, но, в общем, интересно, что преимущества не в том, чтобы считать все "виртуальным" - то есть, метод, вызванный в экземпляре дочернего класса, всегда выполняет дочерний самой версии этого метода. В С# это не так, если родительский метод не помечен "виртуальным" модификатором. Пример:
public class Parent
{
public void NonVirtual() { Console.WriteLine("Non-Virtual Parent"); }
public virtual void Virtual(){ Console.WriteLine("Virtual Parent"); }
}
public class Child : Parent
{
public new void NonVirtual() { Console.WriteLine("Non-Virtual Child"); }
public override void Virtual() { Console.WriteLine("Virtual Child"); }
}
public class Program
{
public static void Main(string[] args)
{
Child child = new Child();
Parent parent = new Child();
var anon = new Child();
child.NonVirtual(); // => Child
parent.NonVirtual(); // => Parent
anon.NonVirtual(); // => Child
((Parent)child).NonVirtual(); // => Parent
child.Virtual(); // => Child
parent.Virtual(); // => Child
anon.Virtual(); // => Child
((Parent)child).Virtual(); // => Child
}
}
В чем конкретно проявляются преимущества не виртуального поведения выше? Единственное, о чем я мог подумать, было "Что, если автор Родитель не хочет, чтобы его метод был виртуальным?" но потом я понял, что не могу придумать для этого хороший вариант использования. Можно утверждать, что поведение класса зависит от того, как работает не виртуальный метод, - но тогда мне кажется, что происходит некоторая плохая инкапсуляция или что метод должен быть запечатан.
Вдоль этих же строк, похоже, что "скрытие" - это, как правило, плохая идея. В конце концов, если был создан объект и методы Child, кажется, что это было сделано по определенной причине для переопределения родителя. И если Child реализует (и скрывает родителей) NonVirtual(), очень легко не получить то, что многие могут считать "ожидаемым" поведением вызова Child:: NonVirtual(). (Я говорю "ожидаемый", потому что иногда легко заметить, что "скрытие" происходит).
Итак, каковы преимущества того, чтобы не позволять всем иметь "виртуальное" поведение? Что является хорошим прецедентом для скрытия не виртуального родителя, если так легко получить неожиданное поведение?
Если кому-то интересно, почему я задаю этот вопрос - я недавно изучал библиотеку DynamicProxy Castle Projects. Единственное препятствие в его использовании заключается в том, что любой метод (или свойство), который вы хотите прокси, должен быть виртуальным. И это не всегда вариант для разработчиков (если у нас нет контроля над источником). Не говоря уже о цели DynamicProxy - избегать связи между вашим прокси-классом и любым поведением, которое вы пытаетесь достичь с помощью прокси-сервера (например, Logging или, возможно, реализация Memoization). И, заставляя виртуальные методы выполнять это, вместо этого достигается очень тонкая, но тупое взаимодействие DynamicProxy со всеми классами, которые он проксирует. Представьте, у вас есть тонна методов, обозначенных виртуальными, даже если они никогда не унаследованы и не переопределены, поэтому любые другие разработчик, смотрящий на код, может задаться вопросом: "Почему они даже виртуальные? позволяют изменить их".
В любом случае, разочарование привело меня к удивлению, что преимущества не виртуального, когда кажется, что все виртуальное, возможно, было более ясным (IMO, я полагаю) и, возможно, (?) имеют больше преимуществ.
EDIT: Маркировка как вики сообщества, так как это похоже на вопрос, который может иметь субъективные ответы