2010-06-30 17 views
31

Immer, wenn ich eine Methode einer Basisklasse außer meiner Implementierung dieser Methode überschreibe, habe ich anscheinend 3 Möglichkeiten.Wie "richtig" überschreiben Sie eine Basisklassenmethode?

1) Rufen Sie base.Method() auf, und stellen Sie dann meine Implementierung bereit.

2) meine Implementierung bereitstellen und dann base.Method nennen()

3) Geben Sie einfach meine Implementierung.

In letzter Zeit habe ich bei der Verwendung einer Bibliothek einige Fehler bemerkt, die eingeführt wurden, weil die Methode nicht wie von der Bibliothek erwartet implementiert wurde. Ich bin mir nicht sicher, ob das auf einem Teil der Bibliothek schlecht ist oder etwas in meinem Verständnis falsch ist.

Ich werde ein Beispiel nehmen.

public class ViewManager { 
    public virtual void Customize(){ 
     PrepareBaseView(); 
    } 
} 

public class PostViewManager { 
    public override void Customize(){ 
     base.Customize(); 
     PreparePostView(); 
    } 
} 


public class PreViewManager { 
    public override void Customize(){ 
     PreparePreView(); 
     base.Customize(); 
    } 
} 


public class CustomViewManager { 
    public override void Customize(){ 
     PrepareCustomView(); 
    } 
} 

Meine Frage hier ist, wie könnte ein Kind Klasse wissen (ohne einen Blick auf Basisklassenimplementierung unter), die Ordnung (oder Option) wird von der übergeordneten Klasse erwartet werden? Gibt es eine Möglichkeit, wie Elternklasse einen der drei Alternativen zu allen abgeleiteten Klassen erzwingen kann?

+1

'PostViewManager',' PreViewManager', 'CustomViewManager' erben von' ViewManager'? In diesem Fall sollten Sie den Code bearbeiten. – LaTeX

Antwort

36

Wie kann eine untergeordnete Klasse (ohne sich die Basisklassenimplementierung anzusehen) wissen, welche Reihenfolge (oder Option) von der übergeordneten Klasse erwartet wird?

Es gibt keine Möglichkeit, dies zu "wissen", wenn Sie eine Methode unterklassifizieren und überschreiben. Die richtige Dokumentation ist hier wirklich die einzige Option.

Gibt es eine Möglichkeit, in der Elternklasse einen der drei Alternativen zu allen abgeleiteten Klassen erzwingen könnte?

Die einzige Möglichkeit hier ist das Problem zu vermeiden. Anstatt zuzulassen, dass die Unterklasse die Methode überschreibt, kann sie als nicht virtuell deklariert werden und eine virtuelle Methode an der entsprechenden Stelle aufrufen.Zum Beispiel, wenn Sie erzwingen möchten, dass Unterklassen „Ihre Version nennen zuerst“, könnten Sie tun:

public class BaseClass { 
    public void Method() // Non-virtual 
    { 
      // Do required work 

      // Call virtual method now... 
      this.OnMethod(); 
    } 

    protected virtual void OnMethod() 
    { // Do nothing 
    } 
} 

Die Unterklassen können dann „überschreiben“ OnMethod und bieten Funktionen, die nach der „Methode“ 's Arbeit geschieht.

Der Grund dafür ist, dass virtuelle Methoden so konzipiert sind, dass eine Unterklasse die Implementierung der übergeordneten Klasse vollständig ersetzen kann. Dies geschieht absichtlich. Wenn Sie dies verhindern möchten, ist es besser, die Methode nicht virtuell zu machen.

+1

Sie haben mich dazu geschlagen. Dies ist das ** Sprödigkeitsgrundklasse ** -Problem. +1 für die Workaround (womit du mich auch besiegst :), das ** Template-Methodenmuster **. Sie könnten sogar das geschützte 'OnMethod'-Abstract erstellen, so dass abgeleitete Klassen wissen, dass sie * eine * eigene Implementierung haben müssen, und außerdem müssen sie keine Basisimplementierung aufrufen (vorausgesetzt, dass es keinen Sinn ergibt, ein "Basis"). – shambulator

+0

+1 Dies wird Sie vor dem Wüten Ihrer Mitentwickler retten. – Marc

+0

@Shambulator - Override ist optional, daher ist es wahrscheinlich nicht vergleichbar mit 'OnMethod' abstract. Es ist immer noch eine gute Option, obwohl –

1

Die kurze Antwort ist nein. Sie können nicht erzwingen, in welcher Reihenfolge das Kind die Basismethode aufruft oder ob es überhaupt aufgerufen wird.

Technisch sollten diese Informationen in der Dokumentation des Stammobjekts enthalten sein. Wenn Sie unbedingt Code vor oder nach dem Code der untergeordneten Klasse ausführen müssen, können Sie Folgendes tun:

1) Erstellen Sie eine nicht virtuelle Funktion in der Basisklasse. Nennen wir es MyFunction

2) Erstellen Sie eine geschützte virtuelle Funktion in der Basisklasse. Nennen wir es _MyFunction

3) Ableiten von Klassen erweitern die _MyFunction-Methode.

4) Lassen Sie MyFunction _MyFunction aufrufen und führen Sie den Code aus, der vor oder nach dem Aufruf ausgeführt werden soll.

Diese Methode ist hässlich und würde viel zusätzlichen Code erfordern, daher empfehle ich, einen Hinweis in die Dokumentation zu schreiben.

+0

Ich frage mich, ob etwas wie PostSharp diese Reihenfolge erzwingen könnte. – FrustratedWithFormsDesigner

0

Die Anforderungen der Basisklasse sollten vom Bibliotheksdesigner dokumentiert werden. Dieses Problem ist der Grund, warum einige Bibliotheken hauptsächlich versiegelte Klassen enthalten.

2

Aus diesem Grund empfinde ich virtuelle Methoden als gefährlich, wenn Sie sie in einer Bibliothek versenden. Die Wahrheit ist, dass Sie nie wirklich wissen, ohne auf die Basisklasse zu schauen, manchmal müssen Sie reflektor anwerfen, Dokumentation lesen oder es mit Versuch und Irrtum angehen.

Wenn ich das Schreiben von Code habe ich immer müde, um die Regel zu folgen, der sagt:

Abgeleitete Klassen, die die geschützte virtuelle Methode überschreiben, sind nicht die Basisklassenimplementierung nennen erforderlich. Die Basisklasse muss weiterhin ordnungsgemäß funktionieren, selbst wenn ihre Implementierung nicht aufgerufen wird.

Dies ist aus http://msdn.microsoft.com/en-us/library/ms229011.aspx entnommen, aber dies ist für Event-Design, obwohl ich glaube, ich lese dies in den Framework Design Guidelines Buch (http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756).

Dies ist jedoch offensichtlich nicht wahr, ASP.NET-Webformulare erfordern beispielsweise einen Basisaufruf auf Page_Load.

Also, lang und kurz, es variiert und leider gibt es keine sofortige Art zu wissen. Wenn ich Zweifel habe, werde ich den Anruf zunächst weglassen.

+0

Was für eine wundervolle Antwort. Meine genauen Gedanken. Abgestimmt. – Xtro

Verwandte Themen