it-swarm.com.de

Verwenden Sie ein neues Schlüsselwort, wenn das Ausblenden beabsichtigt war

Ich habe den folgenden Codeausschnitt, der die Warnung "Neues Schlüsselwort verwenden, wenn das Ausblenden beabsichtigt war" in VS2008 generiert:

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

Die Foo() -Funktion in der Basisklasse ist geschützt, und ich möchte sie einem Komponententest aussetzen, indem ich sie ausschließlich zum Zweck des Komponententests in eine Wrapper-Klasse lege. Das heißt Die Wrapper-Klasse wird für nichts anderes verwendet. Also eine Frage, die ich habe, ist: ist das akzeptierte Praxis?

Zurück zur Warnung new. Warum muss ich in diesem Szenario die übergeordnete Funktion neu einrichten?

54
Guy

Das new macht nur absolut klar, dass Sie wissen, dass Sie über eine vorhandene Methode stampfen. Da der existierende Code protected war, ist es keine so große Sache - Sie können den new sicher hinzufügen, um das Stöhnen zu stoppen.

Der Unterschied kommt, wenn Ihre Methode etwas anderes macht; Jede Variable, die auf die Klasse abgeleitet verweist und Foo() aufruft, würde (auch mit demselben Objekt) etwas anderes tun als eine Variable, die auf die Klasse Basis verweist und aufruft Foo():

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

Dies könnte sich natürlich auf jeden vorhandenen Code auswirken, der über SomeDerived Bescheid weiß und Foo() aufruft - d. H., Es wird jetzt eine völlig andere Methode ausgeführt.

Beachten Sie auch, dass Sie protected internal Markieren und [InternalsVisibleTo] Verwenden können, um Zugriff auf Ihren Komponententest zu erhalten (dies ist die häufigste Verwendung von [InternalsVisibleTo]; Dann Ihre Komponententests) kann direkt ohne die abgeleitete Klasse darauf zugreifen.

69
Marc Gravell

Der Schlüssel ist, dass Sie nicht die Methode überschreiben. Du versteckst es. Wenn Sie es überschreiben würden, bräuchten Sie das Schlüsselwort override (an diesem Punkt würde sich der Compiler beschweren, wenn es nicht virtuell ist, weil Sie kann nicht eine nicht virtuelle Methode überschreiben) .

Sie verwenden das Schlüsselwort new, um sowohl dem Compiler als auch jedem, der den Code liest, mitzuteilen: "Es ist in Ordnung, ich weiß, dass dies nur die Basismethode verbirgt und nicht überschreibt - das wollte ich tun."

Ehrlich gesagt denke ich, dass es selten eine gute Idee ist, Methoden auszublenden - ich würde einen anderen Methodennamen verwenden, wie Craig vorgeschlagen hat -, aber das ist eine andere Diskussion.

38
Jon Skeet

Sie ändern die Sichtbarkeit ohne den Namen. Rufen Sie Ihre Funktion TestFoo auf und es wird funktionieren. Ja, meiner Meinung nach ist es akzeptabel, aus diesem Grund eine Unterklasse zu vergeben.

8
Craig Stuntz

Es gibt immer wieder knifflige Situationen, in denen das Schlüsselwort new zum Ausblenden verwendet werden kann, während es die meiste Zeit vermieden werden kann.

Vor kurzem brauchte ich dieses Schlüsselwort jedoch wirklich, hauptsächlich, weil der Sprache einige andere geeignete Synthaxfunktionen fehlen, um beispielsweise einen vorhandenen Accessor zu vervollständigen:

Wenn Sie eine altmodische Klasse betrachten, wie:

KeyedCollection<TKey, TItem>

Sie werden feststellen, dass der Zugriff auf die Artikel über den Index wie folgt erfolgt:

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

Hat beide { get; set; } Und sie sind natürlich aufgrund der Vererbung von ICollection<T> Und Collection<T> Obligatorisch, aber es gibt nur einen { get; } Für den Zugriff auf die Elemente durch ihre Schlüssel (Ich habe einige Vermutungen zu diesem Design und es gibt viele Gründe dafür. Bitte beachten Sie, dass ich den KeyedCollection<TKey, TItem>) nur zu Illustrationszwecken aufgehoben habe).

Es gibt also nur einen Getter für den Schlüsselzugriff:

TItem this[TKey key] { get; }

Aber was ist, wenn ich die { set; } - Unterstützung hinzufügen möchte? Technisch gesehen ist das nicht so dumm, vor allem, wenn Sie sich nicht an die frühere Definition der Eigenschaft halten, sondern nur an eine Methode. Die einzige Möglichkeit besteht darin, sie explizit zu implementieren eine andere Dummy-Schnittstelle, aber wenn Sie implizit machen möchten, müssen Sie das Schlüsselwort new einfallen lassen, ich verstecke die Accessor-Definition und behalte das get; Basisdefinition und fügen Sie einfach ein Set mit einigen persönlichen Dingen hinzu, damit es funktioniert.

Ich denke, für dieses sehr spezielle Szenario ist dieses Schlüsselwort perfekt anwendbar, insbesondere in Bezug auf einen Kontext, in dem der { get; } - Teil nicht verwendet wird.

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

Dies ist so ziemlich der einzige Trick, um diese Art von Warnung zu vermeiden, da der Compiler Ihnen vorschlägt, dass Sie sich möglicherweise verstecken, ohne zu bemerken, was Sie tun.

1
Perret