2010-10-06 14 views
18

So che non è possibile ereditare i costruttori in C#, ma probabilmente c'è un modo per fare ciò che voglio fare.C#: costruttori ereditari

Ho una classe base che è ereditata da molte altre classi e ha un metodo Init che fa un po 'di inizializzazione prendendo 1 parametro. Tutte le altre classi che ereditano anche bisogno di questo inizializzazione, ma avrei bisogno di creare costruttori separate per tutti loro che vorrebbe in questo modo:

public Constructor(Parameter p) { 
    base.Init(p); 
} 

che viola i principi del tutto a secco! Come posso inizializzare tutte le cose necessarie senza creare dozzine di costruttori?

+2

Peggio della violazione dei principi ASCIUTTO sta violando il principio invariante. 'Init' come nome di un metodo è generalmente un segno forte che gli oggetti sono inutilmente esistenti in stati non validi in cui l'unica cosa per cui sono buoni è la causa di bug. –

+1

Il C# in non segue affatto l'ASCIUTO. Questo può essere fastidioso ma ... onestamente, non puoi dirmi che non sei stanco di digitare 'public',' protected' e 'private' ancora e ancora? –

+1

@ SlippD.Thompson: Questa è un'altra area in cui C++ è in realtà * less * wordy di linguaggi più semplici ... Il precedente che ho appena visto riguardava l'esposizione dei costruttori di base in una classe derivata. –

risposta

47

Non è necessario creare carichi di costruttori, tutti con lo stesso codice; ne crei solo uno, ma le classi derivate chiamano il costruttore di base:

public class Base 
{ 
    public Base(Parameter p) 
    { 
     Init(p) 
    } 

    Init(Parameter p) 
    { 
     // common initialisation code 
    } 
} 

public class Derived : Base 
{ 
    public Derived(Parameter p) : base(p) 
    { 

    } 
} 
+1

Questo è quello di cui ho bisogno. Anche se dovrò creare dei costruttori per le classi che non li hanno, non dovrò ripetere il codice. – Alex

+1

perchè il down-vote? –

+1

Vorrei che C# avesse qualcosa di simile ai costruttori ereditari di C++, è ancora fastidioso chiamare tutti i costruttori di base –

7

modificare la funzione init ad essa è il costruttore della classe base, e poi lo chiamano dagli oggetti ereditati come questo:

public InheritedObject(Parameter p) : base(p) 
{ 
} 

Il costruttore di base verrà richiamato prima di qualsiasi codice nel costruttore sé corre .

2

Qualcosa di simile?

public Constructor(Parameter p) : base(p) { 

} 

E la classe di base:

public Base(Parameter p) 
{ 
    Init(p); 
} 

È anche possibile contrassegnare il metodo Init come virtuale, in modo da poter fare un po 'di override dolce nelle altre classi, se necessario! ;)

public virtual void Init() { } 

e nelle altre classi:

public override void Init() { base.Init(); //Do other stuff } 
+2

Sebbene sia necessario fare molta attenzione chiamando un metodo virtuale da un costruttore - il costruttore della sottoclasse non verrà eseguito quando viene chiamato il metodo sottoposto a override dalla superclasse, quindi le variabili membro ecc non sarebbero state inizializzate. – thecoop

+0

true :) ma troverai il problema molto veloce .. – Arcturus

+1

Il metodo di init virtuale sembra inutile, però. Normalmente dovresti evitare di lavorare nei costruttori, e usarli solo per l'inizializzazione, e se è solo inizializzato, perché non usare semplicemente il costruttore? – AHM

5

L'unico modo per non ripetere la chiamata base.Init è quello di chiamare invece il costruttore di base

class Base 
{ 
    public Base(Parameter p) 
    { 
    this.Init(p) 
    } 

    private void Init(Parameter p) 
    { 
     ... 
    } 
} 

class Inherited : Base 
{ 
    public Inherited(Parameter p) 
    : base(p) 
    { 
     // other constructor logic, but Init is already called. 
    } 
} 
3

Non è possibile ereditare costruttori ma puoi chiamarli dai costruttori dei tuoi figli derivati. Se rendi privato il costruttore predefinito delle classi di base, verrà forzato a selezionare un costruttore di base ogni volta che crei una classe derivata.

class A 
{ 
    protected A(int x) 
    { 

    } 
} 
class B : A 
{ 
    B(int x) 
     : base(x) 
    { 

    } 
}