web-dev-qa-db-ja.com

非表示が意図されている場合は、新しいキーワードを使用します

VS2008で「非表示が意図されている場合は新しいキーワードを使用する」という警告を生成する次のコードスニペットがあります。

_public double Foo(double param)
{
   return base.Foo(param);
}
_

基本クラスのFoo()関数は保護されており、単体テストの目的でのみラッパークラスに配置することで単体テストに公開したいと思います。つまりラッパークラスは他の用途には使用されません。だから私が持っている1つの質問は:これは受け入れられた慣習ですか?

new警告に戻ります。 なぜこのシナリオでオーバーライド関数を新しくしなければならないのですか?

54
Guy

newは、既存のメソッドに踏み込んでいることがわかっていることを完全に明確にします。既存のコードはprotectedであったため、それほど大したことではありません。newを安全に追加してうめき声を止めることができます。

違いは、メソッドが何か異なることをするときに生じます。 派生クラスを参照してFoo()を呼び出す変数は、baseクラスを参照して呼び出すものとは異なる動作をします(同じオブジェクトであっても) 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]_の最も一般的な使用方法です。その後、ユニットテストでアクセスできます)派生クラスなしで直接。

69
Marc Gravell

重要なのは、あなたがnotメソッドをオーバーライドしているということです。あなたはそれを隠しています。オーバーライドする場合は、overrideキーワードが必要になります(その時点で、仮想でない限り、コンパイラはできない非仮想メソッドをオーバーライドするため文句を言うでしょう) 。

newキーワードを使用して、コンパイラーとコードを読んでいる人の両方に、「大丈夫です。これは基本メソッドを隠しているだけで、オーバーライドしないことを知っています。それが私が意図したことです。」

率直に言って、メソッドを非表示にすることはめったに良い考えではないと思います-クレイグが示唆したように、別のメソッド名を使用します-しかし、それは別の議論です。

38
Jon Skeet

名前なしで可視性を変更しています。関数TestFooを呼び出すと、機能します。はい、私見では、この理由でサブクラス化することは許容されます。

8
Craig Stuntz

newキーワードを使用して非表示にすることはできますが、ほとんどの場合は回避することができます。

ただし、最近、このキーワードが本当に必要になりました。これは、主に、たとえば既存のアクセサーを完成させるための適切なシンタックス機能が言語にないためです。

次のような昔ながらのクラスを検討する場合:

KeyedCollection<TKey, TItem>

インデックスを介してアイテムにアクセスするためのアクセサーは次のようになります。

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

{ get; set; }の両方を持ち、ICollection<T>Collection<T>に関する継承のためにもちろん必須ですが、キーを介してアイテムにアクセスするための{ get; }は1つだけです(私は持っていますこの設計についていくつかの推測があり、その理由はたくさんあるので、説明のためだけにKeyedCollection<TKey, TItem>)を選択したことに注意してください。

とにかく、キーアクセス用のゲッターは1つだけです。

TItem this[TKey key] { get; }

しかし、{ set; }サポートを追加したい場合はどうでしょうか。技術的に言えば、特にプロパティの以前の定義から推論を続ける場合、それは単なるメソッドです...唯一の方法は明示的に別のものを実装することですダミーインターフェイスですが、暗黙的に作成する場合は、newキーワードを考え出す必要があります。アクセサ定義を非表示にして、getを保持します。基本的な定義を追加し、個人的なものを詰め込んだセットを追加するだけで機能します。

この非常に特殊なシナリオでは、このキーワードは特に{ get; }部分に持ち込まれないコンテキストに関して、適切に適用できると思います。

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

これは、この種の警告を回避するための唯一のトリックです。コンパイラは、自分が何をしているのか分からずに隠れているかもしれないと示唆しています。

1
Perret