C#: разница между new и override
Сказать по правде я долго над этим не задумывался. Нет, я знал что в C# существует модификатор new и что он скрывает реализацию членов базового класса, также он может менять модификаторы доступа (о чем я со временем забыл). Т.е. если в базовом классе, например, метод определен как публичный, используя модификатор new в наследнике – можно сделать его приватным.
Но на практике я никогда не использовал этот модификатор. Почему? Потому что его использование мне кажется говорит о том, что с кодом что-то не так. Для того чтобы реализовать полиморфизм достаточно и широко распространенных virtual-override. И если в классе потомке приходится скрывать, к примеру, реализацию базового класса. То возможно потомок наследуется не от того базового класса или базовый класс стоит раздробить на более специфицированные.
Как пример приведу два класса:
class Musician { public void PlayPiano() { Console.WriteLine("Я - музыкант, я я играю на рояле"); } public void PlayDrum() { Console.WriteLine("Я - музыкант, я играю на ударных"); } } class Pianist : Musician { new private void PlayDrum() { } new public void Play() { Console.WriteLine("Я - пианист, я играю но рояле"); } }
Пример, конечно, синтетический, но хотело продемонстрировать что использования new можно избежать. Достаточно выделить класс Musician как базовый сделать у него один метод Play и создать два потомка Drummer и Pianist, которые будут переопределять этот метод. Собственно, почему я решил на писать о new и разнице его с virtual-override – потому что меня об этом спросили. И в силу того что практического использования этого модификатора не имел – забыл нюансы. Основная разница между ними заключается в том как они ведут себя при полиморфизме. Итак пусть есть два класса - Музыкант, который играет на музыкальном инструменте, но неизвестно каком:
class Musician { public virtual void Play() { Console.WriteLine("Я - музыкант, но я не знаю на чем я играю"); } }
И класс Пианист, потомок от класса Музыкант, который знает точно, что он играет на рояле:
class Pianist : Musician { public override void Play() { Console.WriteLine("Я - музыкант, я играю но рояле"); } }
Итак вся разница между ними – это что выведется на консоль при вызове метода Play, а точнее какой метод из них будет вызван:
Musician player = new Pianist(); player.Play();
Итак в случае с virtual-override выведется:
Я - музыкант, я играю но рояле
Если же определить метод Play с использованием модификатора new на консоль выведется другое сообщение:
class Pianist : Musician { new public void Play() { Console.WriteLine("Я - музыкант, я играю но рояле"); } }
Код выше выведет:
Я - музыкант, но я не знаю на чем я играю
При использовании new метод Play не перекрывает реализацию базового класса, а подменяет ее своей (по сути прячет ее). Поэтому когда мы сохраняем переменную типа Pianist в переменной базового типа Musician, мы не получим вызова override метода из класса Pianist , так как в не переопределяется, а подменяется метод используя new. При использовании virtual-override происходит виртуальный вызов и будет вызван переопределённый (overriden) метод из класса Pianist. Нашел по этому поводу хорошее обсуждение на stackoverflow. В одном из ответом даже приведена картинка для пояснения. Вот она:
Знать о существовании модификатора new конечно нужно. Но его стоит использовать в исключительных случаях. Возможно, когда исходный код базовых классов недоступен. У меня складывается впечатление что вопрос про разницу new и virtual-override чаще используется на интервью в качестве каверзного вопроса чем на практике.
http://regfordev.blogspot.com/2011/01/c-new-override.html
Компании из статьи
Microsoft Украина | Украинское подразделение компании Microsoft. |