2010-09-26 11 views
63

In quali condizioni dovrei effettuare le chiamate del costruttore :base() e :this() seguendo le parentesi del mio costruttore (o anche in altre posizioni nel codice). Quando vengono chiamate queste buone pratiche e quando sono obbligatorie?base() e questa() migliori pratiche dei costruttori

+0

dispiaciuto per l'ambiguità ... So quello che queste chiamate stanno facendo. Non ero chiaro sullo scenario in cui avrei dovuto o dovuto effettuare queste chiamate. Luoghi in cui, se non li creo, o sono condannato subito o ci sarà un bug latente o una scarsa qualità del codice. Di recente ho avuto un tale mal di testa quindi volevo chiarire questi scenari. - – explorer

risposta

85

: base(...)

Se si omette la chiamata a un costruttore di base si chiamerà automaticamente il costruttore di base di default.

È obbligatorio chiamare esplicitamente un costruttore di base se non esiste un costruttore predefinito.

Anche se esiste un costruttore predefinito, è possibile chiamare un costruttore diverso rispetto al costruttore predefinito. In questo caso, potresti comunque voler utilizzare base(foo, bar) per chiamare un costruttore diverso rispetto al costruttore base.

Non ritengo che sia una cattiva pratica omettere base() quando si desidera chiamare il costruttore predefinito della classe base, anche se se si desidera essere espliciti non vedo alcun danno includendolo. È una questione di gusti.

: this(...)

Questa sintassi consente di chiamare un costruttore con una firma diversa da un altro all'interno della stessa classe. Non è mai obbligatorio farlo, ma a volte può essere utile.

Un esempio di quando può essere utile è il riutilizzo del codice comune nei costruttori. Per esempio in C# 3.5 o prima di poter desidera simulare parametri opzionali su un costruttore:

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

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

Con C# 4.0 parametri opzionali sono ora disponibili che riduce la necessità di questo approccio.

Un modo alternativo per riutilizzare il codice nei costruttori consiste nel calcolarlo in una funzione statica chiamata da ciascun costruttore che desidera utilizzarlo.

5

Cercare "concatenamento concatenamento in C#". In sostanza, sembra che questo:

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

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

aiuta a rimuovere la duplicazione del codice nei costruttori - li diviso in parti di base e specifici.

+0

Grazie. "Costruttore che incatena" era il termine che non ricordavo. – JNappi

4

Si utilizza: base() quando si desidera che il costruttore della classe base venga chiamato automaticamente come prima istruzione del costruttore. : questo() è simile, ma chiama un altro costruttore sulla stessa classe.

In base :() e questo(): è possibile passare come parametri valori costanti o espressione in base ai parametri del costruttore.

È obbligatorio chiamare il costruttore base quando la classe base non ha un costruttore predefinito (uno che non accetta parametri). Non so di un caso in cui: questo() è obbligatorio.

public class ABaseClass 
{ 
    public ABaseClass(string s) {} 
} 

public class Foo : AChildClass 
{ 
    public AChildClass(string s) : base(s) {} //base mandatory 
    public AChildClass() : base("default value") {} //base mandatory 
    public AChildClass(string s,int i) : base(s+i) {} //base mandatory 
} 

public class AnotherBaseClass 
{ 
    public ABaseClass(string s) {} 
    public ABaseClass():this("default value") {} //call constructor above 
} 

public class Foo : AnotherChildClass 
{ 
    public AnotherChildClass(string s) : base(s) {} //base optional 

} 
28

Prima di tutto, quando sono obbligatori.

Quando una classe Derived è derivata da una classe Base, e Base non ha un costruttore di default (senza parametri), Derived deve chiamare base() in modo esplicito con i parametri.

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) { } 
} 

Quando è buona pratica? Ogni volta che si desidera chiamare un costruttore diverso.

Supponiamo di aggiungere, nel mio esempio precedente, il contenuto ai costruttori in Derivato.

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); 
    } 
} 

Si nota la duplicazione qui? È più semplice chiamare il costruttore this().

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

Quindi l'ordine chiamante nell'ultimo esempio sarebbe: 'base (7)', quindi 'Derived (7)', e quindi 'Derived()'. In altre parole, la parte 'this (7)' NON attiverà un 'base()' (supponendo che ci fosse un tale metodo di base). È corretto? – RayLuo

+1

corretto; i costruttori sono sempre concatenati e ogni classe chiama i costruttori della sua classe base. Usando 'this' si riutilizza l'altro costruttore di questa classe (che userà' base', implicitamente senza argomenti o esplicitamente); usando 'base' puoi scegliere quale costruttore della classe base chiamare. – configurator

21

Usa base quando c'è l'eredità, e una classe genitore fornisce già la funzionalità che si sta cercando di raggiungere.

Utilizzare this quando si fa riferimento all'entità corrente (o self), utilizzarla nell'intestazione/firma del costruttore quando non si desidera duplicare funzionalità già definite in un altro costruttore.

In sostanza, con base e questo colpo di testa di un costruttore è quello di mantenere il vostro codice DRY, rendendolo più gestibile e meno prolisso

Ecco un esempio assolutamente privo di senso, ma penso che illustra l'idea di mostrare come i due possono essere usati.

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."); 
    } 
} 

Usage:

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.