Objekte im Konstruktor instanziieren

8

Hat das folgende Vorteile?

%Vor%

Anstatt es so zu machen:

%Vor%

Da bei der Instantiierung die private Member-Variable in jedem Beispiel instanziiert wird, glaube ich nicht, dass es einen Unterschied gibt, aber ich habe es oft genug gesehen, wo ich neugierig bin.

    
Ben Lakey 23.01.2011, 07:45
quelle

3 Antworten

19

In genau dem Fall, den Sie gegeben haben, gibt es keinen Unterschied - aber im Allgemeinen gibt es.

Variableninitialisierungen werden ausgeführt, bevor der Basisklassenkonstruktor aufgerufen wird. Wenn dieser Basiskonstruktor eine virtuelle Methode aufruft, die einige der Instanzvariablen verwendet, können Sie diesen Unterschied sehen.

Spezifische Fans finden Sie in Abschnitt 10.11.2 der C # 4-Spezifikation:

  

Wenn ein Instanzkonstruktor keinen Konstruktorinitialisierer oder einen Konstruktorinitialisierer der Form base (...) hat, führt dieser Konstruktor implizit die Initialisierungen durch, die durch die Variableninitialisierer der Instanzfelder angegeben werden, die in seiner Klasse deklariert sind. Dies entspricht einer Folge von Zuweisungen, die unmittelbar nach dem Eintritt in den Konstruktor und vor dem impliziten Aufruf des direkten Basisklassenkonstruktors ausgeführt werden.

Hier ist ein Beispiel, das das demonstriert:

%Vor%

Ergebnis:

  

x = initialisiert in der Deklaration; y =

Nun, nachdem ich das obige gesagt habe, würde ich mich bemühen, virtuelle Methoden von einem Konstruktor aus aufzurufen. Sie fordern die abgeleitete Klasse grundsätzlich dazu auf, teilweise initialisiert zu arbeiten. Es ist jedoch ein Unterschied, den Sie beachten sollten.

Wie für wo Variablen initialisiert werden ... Ich muss zugeben, dass ich nicht besonders konsequent bin, und ich finde nicht, dass das eigentlich ein Problem ist. Wenn ich einen bestimmten Bias habe, ist es wahrscheinlich, alles zu initialisieren, was zum Zeitpunkt der Deklaration nicht von irgendwelchen Parametern abhängt, und die Variablen, die ich nicht initialisieren kann, ohne zusätzliche Informationen zum Konstruktor zu lassen.

    
Jon Skeet 23.01.2011, 08:53
quelle
5

In Ihrem Fall gibt es keinen wirklichen Unterschied in der Funktionalität. Es gibt jedoch das Problem, herauszufinden, wo und wie alles initialisiert wird. Wenn ich die Initialisierung in den Konstruktor setze, habe ich zwei große Vorteile:

  1. Alles ist an einem Ort initialisiert; Ich muss nicht danach suchen, ob und wo es eingestellt wird.

  2. Wenn ich möchte, kann ich Argumente an den Bar-Konstruktor übergeben, basierend darauf, wie ich Sachen aufstelle. Wenn der Initialisierer außerhalb des Konstruktors ist, bin ich viel begrenzter darin, wie ich Sachen initialisieren kann.

Ehrlich gesagt, hilft die IDE ein wenig mit # 1 ... obwohl es mich von dem Code wegreißt, den ich gerade angesehen habe, sind meine Klassen selten so groß, dass das Wiederauffinden von Sachen ein Problem macht. Wenn ich also # 2 nicht brauche, mache ich es genauso, je nach Projekt und Stimmung. Für größere Projekte möchte ich jedoch alle meine Init-Code an einem Ort haben.

Bearbeiten:

OK, anscheinend gibt es einen Unterschied zwischen den beiden. Aber der Fall, in dem es darauf ankommt, ist selten.

Ich habe die folgenden Klassen erstellt:

%Vor%

Nun, was ich gefunden habe, war ein wenig überraschend und unerwartet (wenn Sie die C # -Spezifikation nicht gelesen haben).

Dies ist der Konstruktor der other -Klasse, der nach:

kompiliert wurde %Vor%

Beachten Sie den Aufruf von Program ::. ctor (der Konstruktor der Basisklasse), der zwischen den zwei ldstr / stfld -Paaren liegt (das sind die s1 und s2 ). Das heißt, wenn der Basiskonstruktor ausgeführt wird, wurde s2 noch nicht festgelegt.

Das Programm gibt als Referenz Folgendes aus:

%Vor%

weil im Konstruktor von% Console.WriteLine(obj) obj.ToString() heißt, was (da das Objekt bereits other ist) other::ToString() war. Da s2 noch nicht gesetzt war, haben wir beim ersten Mal keine "Welt" bekommen. Wenn wir etwas fehleranfälligeres tun als nur Drucksachen, könnte dies echte Probleme verursachen.

Nun, das ist ein hässliches Beispiel, das als pathologischer Fall gedacht ist. Aber es ist ein ausgezeichnetes Argument gegen den Aufruf virtueller Funktionen in Ihrem Konstruktor. Ohne dies zu tun, wäre dieser Bruch nicht möglich gewesen. Das ist das einzige Mal, dass Sie sich wirklich Gedanken um den Unterschied machen müssen: Wenn der Konstruktor Ihrer Basisklasse aufgerufene virtuelle Methoden aufruft, die sich auf die Werte aller Felder verlassen, die im Konstruktor gesetzt werden. Ein ziemlich schmales Fenster der Zerbrechlichkeit, aber ja.

    
cHao 23.01.2011 07:54
quelle
1

Der Unterschied besteht darin, dass Sie die Eigenschaft bar initialisiert haben, nachdem der Konstruktor aufgerufen wurde, und in der Sekunde, bevor der Konstruktor aufgerufen wird. Sie verwenden keine statischen Methoden, daher gibt es keinen Unterschied.

Etwas außerhalb des Themas, aber der beste Weg ist, den Balken außerhalb des Objekts wie folgt zu initialisieren:

%Vor%

Auf diese Weise koppeln Sie nicht Ihre Objekte.

    
smentek 23.01.2011 17:09
quelle

Tags und Links