Является ли метод скрытием когда-либо хорошей идеи

В С# модификатор 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: поскольку скрытие метода происходит только в частном унаследованном классе, оно не должно вызывать путаницы, которая может возникнуть в других случаях использования.