2008-11-12 3 views
23

Ist es eine gute Idee (Konstruktor-Aufrufe zu verschachteln), um überladene New- oder Factory-Style-Methoden zu verschachteln? Dies ist hauptsächlich für einfache Konstruktoren, wo jede Überladung auf der vorherigen aufbaut.Ist die Verschachtelung von Konstruktoren (oder Factory-Methoden) gut, oder sollten alle alle Init-Arbeiten ausführen?

MyClass(arg1) { 
    _arg1 = arg1; 
    _otherField = true; 
    _color="Blue" 
} 
MyClass(arg1, arg2) : this(arg1) { 
    _arg2 = arg2 
} 
MyClass(arg1, arg2, arg3) : this(arg1, ar2) { 
    _arg3 = arg3; 
} 

Oder mit Fabrikmethoden:

static NewInstance(arg1) { 
    _arg1 = arg1;  
} 
static NewInstance(arg1, arg2) { 
    f = NewInstance(arg1); 
    f._arg2 = arg2; 
} 
//... and so on 

ich einige Nachteile auf beiden Seiten sehen kann

  • Nesting versteckt, was der Konstruktor die Funktionalität
  • Nicht Verschachtelung Duplikaten alle tut

Macht das also eine gute Idee, oder richtet es mich auf etwas aus, das ich gerade nicht als Problem sehe? Aus irgendeinem Grund fühle ich mich unbehaglich, weil es die Verantwortung für die Initialisierung teilt.

Bearbeiten: @ Jon Skeet: Ich sehe jetzt, warum dies mich so sehr belastete. Ich habe es rückwärts gemacht! Ich schrieb die ganze Sache und bemerkte es nicht einmal, es roch einfach. Die meisten anderen Fälle, die ich habe (die ich geschrieben habe), tun es so, wie Sie es empfehlen, aber das ist sicherlich nicht die einzige, die ich so gemacht habe. Ich bemerke, dass die komplizierteren, die ich richtig gemacht habe, aber die einfachen, die ich scheinbar schlampig geworden bin. Ich liebe Mikrobearbeitungen. Ich mag auch Akronyme!

Antwort

55

Ich denke, es ist sinnvoll, Konstruktoren zusammen zu ketten, aber ich mache es andersherum - die Version mit weniger Parametern ruft die Version mit mehr Parametern auf. Auf diese Weise wird deutlich, was passiert, und die gesamte "Logik" (jenseits der Standardwerte) befindet sich an einem einzigen Ort. Zum Beispiel:

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

private static int DefaultY 
{ 
    get { return DateTime.Now.Minute; } 
} 

public Foo(int x) : this(x, DefaultY) 
{ 
} 

public Foo() : this(1, DefaultY) 
{ 
} 

Beachten Sie, dass, wenn Sie viele Konstruktorüberladungen haben, können Sie stattdessen statische Factory-Methoden verschieben wollen -, dass in der Regel der Code klarer, sowie die Möglichkeit mehrere Methoden, um den gleichen Satz nehmen macht von Parameter, z

public static XmlDocument FromText(string xml) 

public static XmlDocument FromFile(string filename) 
+2

Einen weiteren Satz von klugen Worten initialisieren! –

+0

Leider funktioniert diese Technik nicht für Standardwerte der Laufzeit.In diesem Beispiel zeigen Sie Konstanten für die optionalen Parameter an. Wenn diese Werte keine Konstanten wären, könnten Sie den Code nicht kompilieren, sondern müssten zu den Werten in den Konstruktorkörpern wechseln. – JeremyDWill

+0

Nein, sie können Laufzeitwerte sein, die durch Ausführen von statischen Methoden/Eigenschaften abgerufen werden. Bearbeitete Antwort, um ein Beispiel zu geben. –

-5

2016 bearbeitet: Noch vor der Zeit, C# radikal zurück oder Beseitigung ihre Aufzeichnungen Unterstützung und Standardkonstruktors Unterstützung für C# 7, vielleicht C# 8 schließlich schneidet.

2015 Bearbeiten: Ich war der Zeit weit voraus. C# 6 und C# 7 machen die Notwendigkeit von Konstruktoren überflüssig.

Wenn Sie in .Net 3.5 entwickeln, empfehle ich nie Konstruktoren zu verwenden. Die einzige Ausnahme, die ich hier belasse, ist, wenn Sie einen Injektionskonstruktor für die Abhängigkeitsinjektion verwenden. Mit .NET 3.5 erstellt sie Objektinitialisierer, die es Ihnen ermöglichen,

var myclass = New MyClass { arg1 = "lala", arg2 ="foo" } 

Dies zu tun, wird die Klasse mit Werten belegen für arg1 und arg2 während verlassen arg3 als

default(typeof(arg3)). 
+6

Und Bang geht jede Gelegenheit, Readonly-Variablen zu verwenden ... –

+2

Ich sehe keine Abhängigkeiten von Zeichenketten und Ganzzahlen - aber sie sind sehr oft Readonly-Mitglieder. Zum Beispiel könnte Ihr "MyClass" -Beispiel gewünscht haben, dass arg1 und arg2 nur gelesen werden. Mit den optionalen und benannten Parametern wird C# 4 glücklicherweise etwas einfacher. –

+2

Also ... was Sie sagen, ist, Konstruktoren mit benannten Werten im Grunde zu verwenden? Oh, und ich mag es wirklich, alle meine privaten Interna bloßzustellen, nur damit ich eine schwierigere Initialisierungssyntax bekommen kann. So toll, wenn ich benannte Params brauche, werde ich sie benutzen. –

Verwandte Themen