Является ли метод сокрытия когда-либо хорошей идеей? - PullRequest
34 голосов
/ 18 апреля 2010

В C # модификатор new может использоваться для скрытия метода базового класса без переопределения метода базового класса.

Я никогда не сталкивался с ситуацией, когда сокрытие метода было лучшим выбором. В каких ситуациях наилучшим выбором является сокрытие методов?

Ответы [ 8 ]

19 голосов
/ 18 апреля 2010

Есть редкие, но очень хорошие причины для сокрытия методов. Эрик Липперт опубликовал отличный пример в своем блоге:

interface IEnumerable<T> : IEnumerable { 
  new IEnumerator<T> GetEnumerator(); 
}

Тем не менее, я думаю, что сокрытие должно быть исключением и использоваться только в редких случаях.

16 голосов
/ 18 апреля 2010

Я склонен использовать его иногда для удобства звонящих, что-то вроде:

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, когда производный класс гарантирует, что пойманное в ловушку животное всегда будет мышью. И полиморфная функциональность остается неизменной.

14 голосов
/ 18 апреля 2010

Часто это хороший выбор, когда вы создаете пользовательские элементы управления и хотите запретить отображение определенных свойств в конструкторе. Иногда свойства не могут быть переопределены, но проектировщик не заботится об этом, он заботится только о том, имеет ли публичное свойство самого низкого уровня атрибут [Browsable].

Например, предположим, что ваш элемент управления не поддерживает заполнение. Свойство Control.Padding не может быть переопределено. Но вы также знаете, что ничего плохого не произойдет, если кто-то установит отступы, просто свойство ничего не делает , делает , поэтому вы не хотите, чтобы ваши пользователи видели это в конструкторе и думаю, что это на самом деле работает. Итак, скройте это:

public class MyControl : Control
{
    [Browsable(false)]
    public new Padding Padding
    {
        get { return base.Padding; }
        set { base.Padding = value; }
    }
}

В этом случае мы буквально используем скрытие элемента, чтобы скрыть элемент - от дизайнера.

Кроме того, я знаю, что есть и другие способы достижения этой цели - это только один из возможных вариантов.

6 голосов
/ 18 апреля 2010

Наиболее распространенный пример, который я могу вспомнить, это такие вещи, как DbCommand против SqlCommand; конкретные типы (SqlCommand и т. д.) обычно скрывают множество методов, чтобы возвращаемые типы свойств / методов отображали правильный тип реализации. Это связано с тем, что сами связанные объекты имеют дополнительные (специфичные для реализации) функции, и вызывающая сторона не хочет выполнять приведение каждый раз, когда они вызывают что-либо.

4 голосов
/ 18 апреля 2010

Да, если вы, например, просто потребитель базового класса, и публикуется новая версия базового класса, внезапно появившийся метод с точно такой же сигнатурой, что и один из методов, которые вы уже реализовали. в вашем производном классе вы должны иметь возможность скрыть метод базового класса, и вы используете new, чтобы прояснить, что вы скрываете метод базового класса ...

1 голос
/ 21 июля 2015

Недавно у меня был случай, когда ключевое слово 'new' было весьма полезным. Я писал модульные тесты для методов в унаследованной кодовой базе, и у некоторых методов в классах, для которых я писал тесты, были скрытые внешние зависимости внутри методов. В то время включение фреймворка для решения проблемы казалось ненужным, поэтому вместо использования фреймворка я унаследовал класс, который хотел протестировать, внутри класса юнит-тестирования. Однако родительский метод не был виртуальным, поэтому его нельзя переопределить. Моим первым решением было просто добавить виртуальное ключевое слово в исходный метод, чтобы его можно было переопределить, и тесты работали отлично. Несмотря на то, что это сработало, я не думаю, что добавление виртуальных ключевых слов в сигнатуры методов только из-за необходимости «имитировать» их в модульном тесте является хорошим решением при проектировании (но я могу ошибаться). Вместо этого использование ключевого слова «new» в дочернем классе позволило мне «избавиться» от зависимостей родительских методов, скрыв оригинальный метод с методом со статическими возвращаемыми значениями, таким образом, написание быстрых модульных тестов для остальных методов также сработало как при замене не виртуальных методов на виртуальные методы.

В общем, я не уверен, что эту технику можно считать хорошей практикой. Однако использование такого рода техники может быть очень полезным при написании набора тестов, чтобы упростить рефакторинг при работе с устаревшим кодом со многими зависимостями, и не имеет автоматизированного набора тестов, с которого можно начать. Скорее всего, тесты можно будет улучшить после завершения работ по рефакторингу.

РЕДАКТИРОВАТЬ: Поскольку скрытие метода происходит только в частном унаследованном классе, это не должно вызывать путаницу, которая может возникнуть в других случаях использования.

1 голос
/ 22 января 2013

Мне пришлось один раз прибегнуть к методу сокрытия. Я использовал стороннюю библиотеку, которая предоставляла не виртуальный метод (это ключ ко всему). Это был метод, который выделял экземпляр чего-либо. Но мне нужно было расширить функциональность этого метода.

Поэтому я использовал ключевое слово «new», чтобы скрыть реализацию базового класса и предоставить свое собственное в производном классе. Как это не значит, что я не вызывал метод базового класса. На самом деле я вызывал метод базового класса, но я делал и другие вещи в своем методе, и в итоге все получилось хорошо.

Так что я бы сказал, что причины будут следующими:

  1. Базовый класс находится в сторонней библиотеке, которую вы не можете контролировать.
  2. Базовый класс имеет не виртуальный метод, который необходимо переопределить.
  3. Всегда обращайте особое внимание на расширение функциональности, а не на ее замену.
  4. И всегда используйте это последнее средство, когда застряли ....:)

Мои 2 цента ...

0 голосов
/ 07 марта 2015

Один раз я использовал его в пользовательском элементе управления 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 будет отображаться в окне свойств.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...