2009-11-29 13 views
182

So che questa è presumibilmente una domanda semplicissima, ma ho lottato con il concetto da un po 'di tempo. La mia domanda è, come si fa a catena i costruttori in C#? Sono nella mia prima classe OOP, quindi sto solo imparando. Non capisco come funziona il concatenamento del costruttore o come implementarlo, o anche perché è meglio che fare solo costruttori senza concatenare.Concatenamento costruttori C#? (Come si fa?)

Gradirei alcuni esempi con una spiegazione.

Quindi, come si fa a inciderli? So che con due va:

public SomeClass this: {0} 

public SomeClass 
{ 
    someVariable = 0 
} 

Ma come si fa con tre, quattro e così via?

Ancora una volta, so che questa è una domanda per principianti, ma mi sto sforzando di capirlo e non so perché.

risposta

275

si utilizza la sintassi standard (utilizzando this come un metodo) per scegliere il sovraccarico, all'interno classe:

class Foo { 
    private int id; 
    private string name; 
    public Foo() : this(0, "") { 
    } 
    public Foo(int id, string name) { 
     this.id = id; 
     this.name = name; 
    } 
    public Foo(int id) : this(id, "") { 
    } 
    public Foo(string name) : this(0, name) { 
    } 
} 

poi:

Foo a = new Foo(), b = new Foo(456,"def"), c = new Foo(123), d = new Foo("abc"); 

Nota anche:

  • puoi concatenare i costruttori sul tipo base usando base(...)
  • si può mettere codice aggiuntivo in ogni costruttore
  • il default (se non si specifica nulla) è base()

Per "perché?":

  • riduzione codice (sempre una buona cosa)
  • necessaria per chiamare una base costruttore non predefinito, ad esempio:

    SomeBaseType(int id) : base(id) {...} 
    

Si noti che è anche possibile utilizzare inizializzatori di oggetti in un modo simile, anche se (senza bisogno di scrivere nulla):

SomeType x = new SomeType(), y = new SomeType { Key = "abc" }, 
     z = new SomeType { DoB = DateTime.Today }; 
+0

Sto facendo alcune concatenamento e devono fare una domanda dal momento che questa risposta è stato votato così altamente. C'è qualche svantaggio nell'avere che ogni costruttore imposta le proprietà che gli sono state passate e quindi chiamare il costruttore predefinito per impostare gli altri? In questo modo non stai codificando i valori di default ('0' e' "" ') in più di un posto (meno possibilità di errore). Ad esempio: 'public Foo (int id): this() {this.id = id; } '? In alternativa, stavo anche considerando: 'public Foo (int id): this (" ") {this.id = id; } '. Solo cercando il modo più logico per incatenarli, apprezzare qualsiasi pensiero. –

+0

C'è un modo per manipolare i valori dell'argomento del costruttore da chiamare nel primo costruttore prima che venga chiamato l'altro costruttore concatenato? – eaglei22

5

Stai chiedendo di questo?

public class VariantDate { 
    public int day; 
    public int month; 
    public int year; 

    public VariantDate(int day) : this(day, 1) {} 

    public VariantDate(int day, int month) : this(day, month,1900){} 

    public VariantDate(int day, int month, int year){ 
    this.day=day; 
    this.month=month; 
    this.year=year; 
    } 

} 
25

Questo è meglio illustrato con un esempio. Imaging abbiamo una persona di classe

public Person(string name) : this(name, string.Empty) 
{ 
} 

public Person(string name, string address) : this(name, address, string.Empty) 
{ 
} 

public Person(string name, string address, string postcode) 
{ 
    this.Name = name; 
    this.Address = address; 
    this.Postcode = postcode; 
} 

Quindi qui abbiamo un costruttore che definisce alcune proprietà, e usa costruttore di concatenamento per consentire di creare l'oggetto con solo un nome, o solo un nome e l'indirizzo. Se crei un'istanza con un solo nome questo invierà un valore predefinito, string.Empty attraverso il nome e l'indirizzo, che quindi invierà un valore predefinito per Codice postale al costruttore finale.

In tal modo si riduce la quantità di codice che hai scritto.Solo un costruttore ha in realtà un codice, non ti stai ripetendo, quindi, ad esempio, se cambi Nome da una proprietà a un campo interno, devi solo cambiare un costruttore - se avresti impostato quella proprietà in tutti e tre i costruttori quello sarebbe tre posti per cambiarlo.

54

Voglio solo portare un punto valido a chiunque cerchi questo. Se lavorerai con versioni .NET precedenti alla 4.0 (VS2010), ti preghiamo di notare che devi creare catene di costruttori come mostrato sopra.

Tuttavia, se soggiornate in 4.0, ho buone notizie. Ora puoi avere un singolo costruttore con argomenti opzionali! Io semplificare l'esempio di classe Foo:

class Foo { 
    private int id; 
    private string name; 

    public Foo(int id = 0, string name = "") { 
    this.id = id; 
    this.name = name; 
    } 
} 

class Main() { 
    // Foo Int: 
    Foo myFooOne = new Foo(12); 
    // Foo String: 
    Foo myFooTwo = new Foo(name:"Timothy"); 
    // Foo Both: 
    Foo myFooThree = new Foo(13, name:"Monkey"); 
} 

Quando si implementa il costruttore, è possibile utilizzare gli argomenti facoltativi dal default sono stati impostati.

Spero vi sia piaciuta questa lezione! Non riesco a credere che gli sviluppatori si siano lamentati del concatenamento dei costrutti e di non essere stati in grado di utilizzare gli argomenti opzionali predefiniti dal 2004/2005! Ora ha impiegato tanto tempo nel mondo dello sviluppo, che gli sviluppatori hanno paura di usarlo perché non sarà retrocompatibile.

+46

Se si utilizza questa tecnica, è necessario essere consapevoli che gli argomenti predefiniti sono impostati in fase di compilazione nel * chiamante *, non nel * callee *. Ciò significa che se si distribuisce un codice come questo in una libreria e un'applicazione utilizza un costruttore con argomenti di default; hai bisogno di ricompilare l'applicazione usando la libreria se cambiano gli argomenti predefiniti. Alcune persone considerano gli argomenti predefiniti nelle interfacce pubbliche intrinsecamente pericolose a causa di questo trucco. – Chuu

+1

Un altro inconveniente con approccio di default degli argomenti è che se si hanno per esempio due argomenti di default nel costruttore, non è possibile chiamarlo solo con il secondo. Nell'esempio qui, dovresti compilare l'errore per: 'Foo myFooOne = new Foo (" ");' –

9

ho una classe diario e quindi non sto scrivendo impostando i valori più e più volte

public Diary() { 
    this.Like = defaultLike; 
    this.Dislike = defaultDislike; 
} 

public Diary(string title, string diary): this() 
{ 
    this.Title = title; 
    this.DiaryText = diary; 
} 

public Diary(string title, string diary, string category): this(title, diary) { 
    this.Category = category; 
} 

public Diary(int id, string title, string diary, string category) 
    : this(title, diary, category) 
{ 
    this.DiaryID = id; 
} 
2

Spero seguente esempio far luce sul costruttore di concatenamento.
ad esempio, mi si aspetta che l'utente passi una directory al costruttore , l'utente non sa quale directory deve passare e decide di consentire a di assegnare la directory predefinita. fai un passo avanti e assegni una directory predefinita che pensi che funzioni .

BTW, ho usato LINQPad per questo esempio nel caso in cui ti stia chiedendo cosa sia * .Dump().
applausi

void Main() 
{ 

    CtorChaining ctorNoparam = new CtorChaining(); 
    ctorNoparam.Dump(); 
    //Result --> BaseDir C:\Program Files (x86)\Default\ 

    CtorChaining ctorOneparam = new CtorChaining("c:\\customDir"); 
    ctorOneparam.Dump();  
    //Result --> BaseDir c:\customDir 
} 

public class CtorChaining 
{ 
    public string BaseDir; 
    public static string DefaultDir = @"C:\Program Files (x86)\Default\"; 


    public CtorChaining(): this(null) {} 

    public CtorChaining(string baseDir): this(baseDir, DefaultDir){} 

    public CtorChaining(string baseDir, string defaultDir) 
    { 
     //if baseDir == null, this.BaseDir = @"C:\Program Files (x86)\Default\" 
     this.BaseDir = baseDir ?? defaultDir; 
    } 
} 
0

C'è un altro punto importante nel costruttore concatenamento: ordine. Perché? Supponiamo di avere un oggetto costruito in fase di esecuzione da un framework che si aspetta che sia il costruttore predefinito. Se si desidera essere in grado di passare i valori pur avendo la possibilità di passare gli argomenti del costruttore quando si desidera, questo è estremamente utile.

Potrei ad esempio avere una variabile di supporto che viene impostata su un valore predefinito dal costruttore predefinito ma che può essere sovrascritta.

public class MyClass 
{ 
    private IDependency _myDependency; 
    MyClass(){ _myDependency = new DefaultDependency(); } 
    MYClass(IMyDependency dependency) : this() { 
    _myDependency = dependency; //now our dependency object replaces the defaultDependency 
    } 
} 
1

Che cosa si intende per "Catena di montaggio"?
Si utilizza per chiamare un costruttore da un altro costruttore.

In che modo è possibile implementare "Constructor Chain"?
Utilizzare la parola chiave ": this (yourProperties)" dopo la definizione di costruttore. per esempio:

Class MyBillClass 
{ 
    private DateTime requestDate; 
    private int requestCount; 

    public MyBillClass() 
    { 
     /// ===== we naming "a" constructor ===== /// 
     requestDate = DateTime.Now; 
    } 
    public MyBillClass(int inputCount) : this() 
    { 
     /// ===== we naming "b" constructor ===== /// 
     /// ===== This method is "Chained Method" ===== /// 
     this.requestCount= inputCount; 
    } 
} 

Perché è utile?
Un motivo importante è la riduzione della codifica e la prevenzione del codice duplicato.come codice ripetuto per l'inizializzazione della proprietà Supponiamo che alcune proprietà in classe debbano essere inizializzate con un valore specifico (nel nostro esempio, requestDate). E la classe ha 2 o più costruttore. Senza "Constructor Chain", è necessario ripetere il codice di inizializzazione in tutti i costruttori di classe.

Come funziona? (Oppure, qual è la sequenza di esecuzione in "Constructor Chain")?
nell'esempio sopra, il metodo "a" verrà eseguito per primo e quindi la sequenza di istruzioni tornerà al metodo "b". In altre parole, il codice di cui sopra è uguale con qui sotto:

Class MyBillClass 
{ 
    private DateTime requestDate; 
    private int requestCount; 

    public MyBillClass() 
    { 
     /// ===== we naming "a" constructor ===== /// 
     requestDate = DateTime.Now; 
    } 
    public MyBillClass(int inputCount) : this() 
    { 
     /// ===== we naming "b" constructor ===== /// 
     // ===== This method is "Chained Method" ===== /// 

     /// *** --- > Compiler execute "MyBillClass()" first, And then continue instruction sequence from here 
     this.requestCount= inputCount; 
    } 
}