55

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

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

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

new警告に戻ります。このシナリオでオーバーライド関数を新しくする必要があるのはなぜですか?

4

4 に答える 4

69

これ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]。その後、単体テストは派生クラスなしで直接アクセスできます。

于 2009-01-16T16:35:53.517 に答える
40

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

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

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

于 2009-01-16T16:38:59.173 に答える
8

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

于 2009-01-16T16:36:22.360 に答える
1

newほとんどの場合は回避できる一方で、キーワードを非表示に使用できるというトリッキーな状況が常に見つかります。

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

次のような昔ながらのクラスを考えてみます。

KeyedCollection<TKey, TItem>

項目のトラフ インデックスにアクセスするためのアクセサーは次のとおりです。

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

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

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

TItem this[TKey key] { get; }

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

この非常に具体的なシナリオでは、このキーワードは完全に適用可能であると思います{ get; }

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

これが、この種の警告を回避するためのほぼ唯一のトリックです。これは、コンパイラが、自分が何をしているのか気付かずに隠れている可能性があることを示唆しているためです。

于 2014-07-24T06:07:32.160 に答える