Используйте новое ключевое слово, если скрытие было предназначено
у меня есть следующий фрагмент кода, который генерирует предупреждение "использовать новое ключевое слово, если скрытие было предназначено" в VS2008:
public double Foo(double param)
{
return base.Foo(param);
}
The Foo()
функция в базовом классе защищена, и я хочу подвергнуть ее модульному тесту, поместив ее в класс-оболочку исключительно с целью модульного тестирования. Т. е. класс-оболочка не будет использоваться ни для чего другого. Так что один вопрос у меня есть: это общепринятая практика?
обратно в new
предупреждение. почему я должен создать переопределяющую функцию в этом сценарии?
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 { ... } }
это почти единственный трюк, чтобы избежать такого рода предупреждения, потому что компилятор предлагает вам, что вы, возможно, скрываетесь, не понимая, что вы делаете.