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


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

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

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

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

4 54

4 ответа:

The 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] чтобы обеспечить доступ к вашему модульному тесту (это наиболее распространенное использование [InternalsVisibleTo]; тогда ваши модульные тесты могут получить доступ к нему напрямую без производного класса.

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

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

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

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

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

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

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

KeyedCollection<TKey, TItem>

вы заметите, что accesor для обработки элементов корыто индекс:

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

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

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

TItem this[TKey key] { get; }

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

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

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

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