Подтвердить что ты не робот

Использовать новое ключевое слово, если целью было скрытие

У меня есть следующий фрагмент кода, который генерирует предупреждение "Использовать новое ключевое слово, если скрытие предназначено" в VS2008:

public double Foo(double param)
{
   return base.Foo(param);
}

Функция Foo() в базовом классе защищена, и я хочу показать ее в unit test, поместив ее в класс оболочки только для целей модульного тестирования. То есть класс-оболочка не будет использоваться ни для чего другого. Итак, у меня есть один вопрос: это принятая практика?

Вернуться к предупреждению new. Зачем мне вводить новую переопределяющую функцию в этом сценарии?

4b9b3361

Ответ 1

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

Разница возникает, когда ваш метод делает что-то другое; любая переменная, которая ссылается на производный класс и вызовы Foo(), будет делать что-то другое (даже с тем же объектом), что и тот, который ссылается на базовый класс и вызывает Foo():

SomeDerived obj = new SomeDerived();
obj.Foo(); // runs the new code
SomeBase objBase = obj; // still the same object
objBase.Foo(); // runs the old code

Это, очевидно, может повлиять на любой существующий код, который знает о SomeDerived и вызывает Foo() - то есть теперь он запускает совершенно другой метод.

Также обратите внимание, что вы можете пометить его protected internal и использовать [InternalsVisibleTo] для обеспечения доступа к вашему unit test (это наиболее распространенное использование [InternalsVisibleTo], тогда ваши модульные тесты могут получить к нему доступ напрямую без производный класс.

Ответ 2

Ключ в том, что вы не переопределяете метод. Ты скрываешь это. Если вы переопределили это, вам понадобится ключевое слово override (в какой момент, если он не будет виртуальным, компилятор будет жаловаться, потому что вы не можете переопределить не виртуальный метод).

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

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

Ответ 3

Вы меняете видимость без имени. Вызовите свою функцию TestFoo, и она будет работать. Да, IMHO это приемлемо для подкласса по этой причине.

Ответ 4

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

Однако в последнее время мне действительно нужно это ключевое слово, главным образом потому, что на языке отсутствуют какие-то другие функции synthax для завершения существующего аксессора, например:

Если вы считаете старомодный класс вроде:

KeyedCollection<TKey, TItem>

Вы заметите, что accereor для доступа к индексу с индексами товаров:

TItem this[Int32 index] { get; set; }

Имеет как { get; set; }, так и они, конечно, обязательны из-за наследования относительно ICollection<T> и Collection<T>, но есть только один { get; } для доступа к элементам через их ключи (у меня есть некоторые догадки об этом дизайне и для этого есть много причин, поэтому учтите, что я взял KeyedCollection<TKey, TItem>) только для иллюстраций).

Во всяком случае, для доступа к ключам есть только один геттер:

TItem this[TKey key] { get; }

Но как насчет того, хочу ли я добавить поддержку { set; }, технически говоря это не так глупо, особенно если вы продолжаете рассуждать о прежнем определении свойства, это всего лишь метод... единственный способ - реализовать явно другой фиктивный интерфейс, но если вы хотите сделать неявным, вы должны придумать ключевое слово new, я скрываю определение accessor, сохраняя get; базовое определение и просто добавьте набор, наполненный некоторыми личными вещами, чтобы заставить его работать.

Я думаю, что для этого очень специфического сценария это ключевое слово применимо, в частности, в контексте контекста, в котором нет части { get; }.

  public new TItem this[TKey key]
  { 
      get { return base... }
      set { ... }
  }

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