Является ли метод скрытием когда-либо хорошей идеи
В С# модификатор new
может использоваться для скрытия метода базового класса без переопределения метода базового класса.
Я никогда не сталкивался с ситуацией, когда лучший способ был спрятать метод. Существуют ли какие-либо ситуации, когда метод скрытия является лучшим выбором?
Ответы
Ответ 1
Есть редкие, но очень хорошие причины для использования метода скрытия. Эрик Липперт опубликовал отличный пример в своем блоге:
interface IEnumerable<T> : IEnumerable {
new IEnumerator<T> GetEnumerator();
}
Однако я считаю, что скрытие должно быть исключением и использоваться только экономно.
Ответ 2
Я обычно использую его для удобства для звонящих, например:
abstract public class Animal { }
public class Mouse : Animal { }
public class AnimalTrap
{
public Animal TrappedAnimal { get; }
}
public class MouseTrap : AnimalTrap
{
new public Mouse TrappedAnimal
{
get { return (Mouse)base.TrappedAnimal; }
}
}
Таким образом, вызывающему не нужно бросать в Mouse
себя, когда производный класс гарантирует, что пойманное животное всегда будет мышью. И полиморфная функциональность остается неповрежденной.
Ответ 3
Это часто хороший выбор, когда вы создаете настраиваемые элементы управления и хотите предотвратить появление определенных свойств в дизайнере. Иногда свойства не являются переопределяемыми, но конструктор не заботится об этом, он заботится только о том, имеет ли публичное свойство нижнего уровня атрибут [Browsable]
.
Например, скажем, что ваш элемент управления не поддерживает дополнение. Свойство Control.Padding не является допустимым. Но вы также знаете, что ничего плохого не произойдет, если кто-то задает заполнение, это просто, что свойство ничего не делает, поэтому вы не хотите, чтобы ваши пользователи видели его в дизайнере и думали, что он действительно работает. Итак, скройте его:
public class MyControl : Control
{
[Browsable(false)]
public new Padding Padding
{
get { return base.Padding; }
set { base.Padding = value; }
}
}
В этом случае мы буквально используем элемент, скрывающий скрывать член - от конструктора.
В стороне, я знаю, что есть другие способы достижения этой цели - это всего лишь один из возможных вариантов.
Ответ 4
Самый распространенный пример, который я могу здесь назвать, - это такие вещи, как DbCommand
vs SqlCommand
; конкретные типы (SqlCommand
и т.д.) обычно выполняют много методов, скрывая, чтобы возвращаемые типы свойств/методов отображали правильный тип реализации. Это связано с тем, что у связанных объектов есть дополнительные (специфичные для реализации) функции, и вызывающий не хочет, чтобы при каждом нажатии они вызывали что-либо.
Ответ 5
Да, если вы, например, публикуете только одного пользователя базового класса и публикуете новую версию базового класса, то внезапно есть метод с той же самой сигнатурой, что и один из методов, которые вы уже реализовали в производном классе вы должны уметь скрыть метод базового класса, и вы используете new
, чтобы было ясно, что вы скрываете метод базового класса...
Ответ 6
Мне приходилось прибегать к методу, скрывающемуся однажды. Я использовал стороннюю библиотеку, которая предоставила метод, который был не виртуальным (это ключ к всему). Это был метод, который выделял экземпляр чего-то. Но мне нужно расширить функциональность этого метода.
Поэтому я использовал ключевое слово "новое", чтобы скрыть реализацию базового класса и предоставить свой собственный в производном классе. Как это не означает, что я не называл метод базового класса. Фактически я действительно вызывал метод базового класса, но я тоже делал другие вещи в своем методе, и в итоге все получилось хорошо.
Итак, я бы сказал, что причины следующие:
- Базовый класс находится в сторонней библиотеке, в которой у вас нет контроля.
- У базового класса есть не виртуальный метод, который необходимо переопределить.
- Всегда уделяйте особое внимание расширению функциональности, не заменяя ее.
- И всегда используйте это последнее средство, когда застряли....:)
Мои 2 цента...
Ответ 7
Один раз я использовал его в пользовательском элементе управления winforms. Мой пользовательский элемент управления переопределяет свойство Text
, и я хочу поднять событие всякий раз, когда он изменяется. Базовый класс Control
поставляется с событием TextChanged
, однако базовое событие имеет атрибуты, наложенные на него, чтобы он не отображался в дизайнере или в intellisense. Поскольку мы используем событие в нашем пользовательском элементе управления, это нежелательно, поэтому мы делаем следующее:
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler TextChanged
{
add { base.TextChanged += value; }
remove { base.TextChanged -= value; }
}
Обработчики событий по-прежнему будут добавляться в одно и то же событие независимо от типа ссылки, которая используется для доступа к нему, но ссылки производного типа будут иметь событие TextChanged
, отображаемое в intellisense, и когда наш элемент управления будет помещен в форме в дизайнере в окне свойств появится событие TextChanged
.
Ответ 8
Недавно у меня был случай, когда ключевое слово "новое" было весьма полезным. Я писал модульные тесты для методов в устаревшей базе кода, а некоторые из методов в классах, которые я писал для тестов, содержал внешние зависимости, скрытые внутри методов. В то же время включение насмешливой структуры для решения проблемы казалось ненужным, поэтому вместо использования насмешливой структуры я унаследовал класс, который я хотел протестировать внутри класса unit test. Однако родительский метод не был виртуальным, поэтому его нельзя было переопределить. Моим первым решением было просто добавить ключевое слово virtual к исходному методу, чтобы он был переопределен, и тесты отлично работали. Несмотря на то, что это сработало, я не думаю, что добавление виртуальных ключевых слов в сигнатуры методов только из-за необходимости "издеваться" над ним в unit test является хорошим дизайнерским решением (но я могу ошибаться). Вместо этого использование "нового" ключевого слова в дочернем классе позволило мне "избавиться" от зависимостей родительских методов, спрятав исходный метод с помощью метода со статическими значениями возврата, таким образом, написав быстрые модульные тесты для остальной части обработанных методов как при изменении не виртуальных методов на виртуальные методы.
В целом, я не уверен, что эту технику можно считать хорошей практикой. Однако использование такого метода может быть очень полезно при написании набора тестов, чтобы облегчить рефакторинг при работе с устаревшим кодом со многими зависимостями и не иметь автоматизированного набора тестов для начала. Тесты, скорее всего, будут улучшены при завершении работы по рефакторингу.
EDIT: поскольку скрытие метода происходит только в частном унаследованном классе, оно не должно вызывать путаницы, которая может возникнуть в других случаях использования.