2010-09-26 11 views
63

Unter welchen Bedingungen soll ich die :base() und :this() Konstruktoraufrufe nach den Klammern meines Konstruktors (oder sogar an anderen Stellen im Code) machen. Wann sind diese Anrufe bewährte Praktiken und wann sind sie verbindlich?base() und this() Konstruktoren Best Practices

+0

sorry für die Mehrdeutigkeit ... Ich weiß, was diese Anrufe machen. Ich war einfach nicht klar über das Szenario, wenn ich diese Anrufe machen sollte oder muss. Orte, an denen ich, wenn ich sie nicht mache, entweder sofort zum Scheitern verurteilt bin oder einen latenten Fehler oder eine schlechte Codequalität. Ich hatte kürzlich solche Kopfschmerzen, deshalb wollte ich diese Szenarien klären. - – explorer

Antwort

85

: base(...)

Wenn Sie den Anruf an einen Basiskonstruktor auslassen wird es den Standard Basiskonstruktor automatisch aufrufen.

Es ist zwingend erforderlich, einen Basiskonstruktor explizit aufzurufen, wenn kein Standardkonstruktor vorhanden ist.

Auch wenn es einen Standardkonstruktor gibt, möchten Sie vielleicht immer noch einen anderen Konstruktor als den Standardkonstruktor aufrufen. In diesem Fall möchten Sie möglicherweise weiterhin base(foo, bar) verwenden, um einen anderen Konstruktor als den Basiskonstruktor aufzurufen.

Ich halte es nicht für eine schlechte Praxis, base() wegzulassen, wenn Sie den Standardkonstruktor der Basisklasse aufrufen möchten. Wenn Sie jedoch explizit sein möchten, sehe ich keinen Schaden darin. Es ist Geschmackssache.

: this(...)

Diese Syntax ermöglicht es Ihnen, einen Konstruktor mit einer anderen Signatur von einem anderen innerhalb der gleichen Klasse zu nennen. Dies ist niemals zwingend erforderlich, kann aber manchmal nützlich sein.

Ein Beispiel, wenn es nützlich sein kann, ist die Wiederverwendung von allgemeinem Code in den Konstruktoren. Zum Beispiel in C# 3.5 oder bevor Sie optionale Parameter auf einem Konstruktor simulieren möchten:

Foo(int x, int y) 
{ 
    this.x = x; 
    this.y = y; 
} 

Foo(int x) : this(x, 10) {} // y defaults to 10 

Mit C# 4.0 optionale Parameter sind jetzt verfügbar, die die Notwendigkeit dieser Ansatz reduziert.

Eine alternative Möglichkeit, Code in Konstruktoren wiederzuverwenden, besteht darin, ihn in eine statische Funktion zu zerlegen, die von jedem Konstruktor aufgerufen wird, der sie verwenden möchte.

5

Suchen Sie nach "Konstruktor Verkettung in C#". Grundsätzlich sieht es wie folgt aus:

MyClass():base() //default constructor calling superclass constructor 
{ 
} 

MyClass(int arg):this() //non-basic constructor calling base constructor 
{ 
    //extra initialization 
} 

Es hilft Code-Duplizierung in Konstrukteuren entfernen - spalten sie in grundlegende und spezifische Teile.

+0

Danke. "Konstrukteurverkettung" war der Begriff, an den ich mich nicht erinnern konnte. – JNappi

4

Sie verwenden: base(), wenn der Konstruktor der Basisklasse automatisch als erster Befehl Ihres Konstruktors aufgerufen werden soll. : this() ist ähnlich, ruft aber einen anderen Konstruktor derselben Klasse auf.

In base :() und this(): Sie können als Parameter konstante Werte übergeben, oder einen Ausdruck basierend auf Parametern Ihres Konstruktors.

Es ist obligatorisch, den Basiskonstruktor aufzurufen, wenn die Basisklasse keinen Standardkonstruktor hat (einen, der keine Parameter akzeptiert). Ich kenne keinen Fall, in dem: das() obligatorisch ist.

28

Zunächst einmal, wenn sie obligatorisch sind.

Wenn eine Klasse Derived von einer Klasse abgeleitet ist Base und Base keinen Standard (parameterlos) Konstruktor, Derivedbase() explizit mit Parametern aufrufen müssen.

public class Base { 
    public Base(int i) { } 
} 


public class Derived : Base { 
    // public Derived() { } wouldn't work - what should be given for i? 
    public Derived() : base(7) { } 
    public Derived(int i) : base(i) { } 
} 

Wann ist es gute Praxis? Wann immer Sie einen anderen Konstruktor aufrufen möchten.

Angenommen, Sie fügen in meinem vorherigen Beispiel Inhalt zu den Konstruktoren in Abgeleitet hinzu.

public class Derived : Base { 
    // public Derived() { } wouldn't work - what should be given for i? 
    public Derived() : base(7) { 
     Console.WriteLine("The value is " + 7); 
    } 
    public Derived(int i) : base(i) { 
     Console.WriteLine("The value is " + i); 
    } 
} 

Sie bemerken die Duplizierung hier? Es ist einfacher, den Konstruktor this() aufzurufen.

public class Derived : Base { 
    // public Derived() { } wouldn't work - what should be given for i? 
    public Derived() : this(7) { } 
    public Derived(int i) : base(i) { 
     Console.WriteLine("The value is " + i); 
    } 
} 
+0

Die Reihenfolge der Aufrufe im letzten Beispiel wäre also: "base (7)" und dann "Derived (7)" und dann "Derived()". Mit anderen Worten, der 'this (7)' -Teil selbst löst KEINE 'base()' aus (vorausgesetzt, es gab eine solche Basismethode). Ist es richtig? – RayLuo

+1

Korrigieren; Die Konstruktoren sind immer verkettet, und jede Klasse ruft die Konstruktoren ihrer Basisklasse auf. Mit 'this' können Sie den anderen Konstruktor dieser Klasse wiederverwenden (der selbst 'base' verwendet, entweder implizit ohne Argumente oder explizit); Mit 'base' können Sie auswählen, welcher Basisklassenkonstruktor aufgerufen werden soll. – configurator

21

Verwendung base wenn es Vererbung und eine Elternklasse bietet bereits die Funktionalität, die Sie erreichen wollen. Verwenden Sie this Wenn Sie die aktuelle Entität (oder self) referenzieren möchten, verwenden Sie sie in der Header/Signatur des Konstruktors, wenn Sie die Funktionalität, die bereits in einem anderen Konstruktor definiert ist, nicht duplizieren möchten.

Grundsätzlich mit Basis und dies in einem Header-Konstruktor ist der Code DRY zu halten, ist es besser verwaltbar und weniger ausführlich

Hier machte ein absolut sinnlos Beispiel, aber ich denke, es ist die Idee zeigt zeigen, wie die zwei können benutzt werden.

class Person 
{ 
    public Person(string name) 
    { 
     Debug.WriteLine("My name is " + name); 
    } 
} 

class Employee : Person 
{ 
    public Employee(string name, string job) 
     : base(name) 
    { 
     Debug.WriteLine("I " + job + " for money."); 
    } 

    public Employee() : this("Jeff", "write code") 
    { 
     Debug.WriteLine("I like cake."); 
    } 
} 

Verbrauch:

var foo = new Person("ANaimi"); 
// output: 
// My name is ANaimi 

var bar = new Employee("ANaimi", "cook food"); 
// output: 
// My name is ANaimi 
// I cook food for money. 

var baz = new Employee(); 
// output: 
// My name is Jeff 
// I write code for money. 
// I like cake.