Mir wurde diese Frage von einem Kollegen gestellt, ob wir immer einen Standardkonstruktor in eine Klasse aufnehmen sollen. Wenn ja warum? Wenn nein, warum nicht?
Beispiel
public class Foo {
Foo() { }
Foo(int x, int y) {
...
}
}
Ich bin auch daran interessiert, dies von Experten zu beleuchten.
c#
.net
clr
default-constructor
Mond
quelle
quelle
Antworten:
Sie müssen berücksichtigen, dass der Compiler einen Standardkonstruktor für Sie generiert, wenn Sie keinen überladenen Konstruktor bereitstellen. Das heißt, wenn Sie nur haben
public class Foo { }
Der Compiler generiert dies wie folgt:
public class Foo { public Foo() { } }
Sobald Sie jedoch den anderen Konstruktor hinzufügen
public class Foo { public Foo(int x, int y) { // ... } }
Der Compiler generiert den Standardkonstruktor nicht mehr automatisch für Sie. Wenn die Klasse bereits in einem anderen Code verwendet wurde, der auf dem Vorhandensein eines Standardkonstruktors beruhte
Foo f = new Foo();
, würde dieser Code jetzt beschädigt.Wenn Sie nicht möchten, dass jemand die Klasse ohne Angabe von Daten initialisieren kann, sollten Sie einen Standardkonstruktor erstellen
private
, der explizit darauf hinweist, dass Sie verhindern, dass Instanzen ohne Eingabedaten erstellt werden.Es gibt jedoch Situationen, in denen ein Standardkonstruktor (öffentlich oder privat) bereitgestellt werden muss. Wie bereits erwähnt, erfordern einige Serialisierungstypen einen Standardkonstruktor. Es gibt auch Zeiten, in denen eine Klasse mehrere parametrisierte Konstruktoren hat, aber auch eine Initialisierung auf "niedrigerer Ebene" erfordert. In diesem Fall kann ein privater Standardkonstruktor verwendet werden, der von den parametrisierten Konstruktoren verkettet wird.
public class Foo { private Foo() { // do some low level initialization here } public Foo(int x, int y) : this() { // ... } public Foo(int x, int y, int z) : this() { // ... } }
quelle
public
Modifikatoren (Klassenmitglieder sindprivate
standardmäßig) ...Foo f = new Foo();
. Sobald Sie jedoch die Klasse in die im dritten Beispiel gezeigte ändern,Foo f = new Foo();
wird ein Compilerfehler verursacht - das war mein Punkt. Solange Sie keine Konstruktoren haben, fügt der Compiler den Standardkonstruktor für Sie hinzu. Sobald Sie fügen alle anderen Konstruktor, fügt der Compiler nicht mehr den Standard - Konstruktor und Code, der auf sie vorhanden Pausen verlassen zu sein.Einige Dinge (wie die Serialisierung) erfordern einen Standardkonstruktor. Darüber hinaus sollte ein Standardkonstruktor jedoch nur hinzugefügt werden, wenn dies sinnvoll ist.
Wenn beispielsweise die Eigenschaften
Foo.X
undFoo.Y
nach der Erstellung unveränderlich sind, ist ein Standardkonstruktor nicht wirklich sinnvoll. Selbst wenn es für ein "leeres" Foo verwendet würde, wäre ein statischerEmpty
Accessor besser auffindbar.quelle
ISerializable
Sie einen Konstruktor (private
falls versiegelt,protected
andernfalls) mit der SignaturClassName(SerializationInfo info, StreamingContext context)
, die die Implementierung von widerspiegelt , und fügen Sie ihn hinzuISerializable.GetObjectData
.Ich würde nein sagen , definitiv nicht immer . Angenommen, Sie haben eine Klasse mit einigen schreibgeschützten Feldern, die auf einen bestimmten Wert initialisiert werden müssen, und es gibt keine vernünftigen Standardeinstellungen (oder Sie möchten nicht, dass es solche gibt)? In diesem Szenario halte ich einen parameterlosen Konstruktor nicht für sinnvoll.
quelle
Ein Standardkonstruktor ist nur dann eine gute Idee, wenn es sinnvoll ist, ein solches Objekt zu haben.
Wenn Sie von einem solchen Konstruktor ein Objekt erzeugen, das sich nicht in einem gültigen Zustand befindet, kann es nur einen Fehler einführen.
quelle
Ja Es ist besser, einen Standardkonstruktor zu haben, um Verwirrung zu vermeiden. Ich habe gesehen, dass Leute in einem Standardkonstruktor nichts tun (selbst in Microsoft-eigenen Klassen), es aber trotzdem gerne behalten, da Objekte automatisch Standard (Typ) erhalten. Die Klassen, die keinen Standardkonstruktor angeben, werden von .NET automatisch für Sie hinzugefügt.
Serialisierung benötigt Standardkonstruktor, wenn Sie vorhandene Serializer verwenden, da dies für Allzweck-Serializer sinnvoll ist. Andernfalls müssen Sie Ihre eigene Implementierung erstellen.
quelle
ISerializable
Sie einen Konstruktor (private
falls versiegelt,protected
andernfalls) mit der SignaturClassName(SerializationInfo info, StreamingContext context)
, die die Implementierung von widerspiegelt , und fügen Sie ihn hinzuISerializable.GetObjectData
.Beachten Sie bei der Verwendung von struct anstelle von class, dass es keine Möglichkeit gibt , den Standardkonstruktor wegzulassen, und dass Sie ihn auch nicht selbst definieren können. Stellen Sie daher unabhängig davon, welche Konstruktoren Sie definieren, sicher, dass der Standardstatus des struct (wenn alle Variablen auf ihren Standardzustand gesetzt sind (normalerweise 0 für Werttypen und null für Referenztypen), wird Ihre Implementierung der Struktur nicht unterbrochen.
quelle
In den meisten Fällen ist ein Standardkonstruktor eine gute Idee. Da Sie jedoch das Wort "immer" verwenden, ist nur ein Gegenbeispiel erforderlich. Wenn Sie sich das Framework ansehen, werden Sie viel finden. Zum Beispiel System.Web.HttpContext.
quelle
Ein generischer Typ kann nur mit C # -Mitteln (ohne Reflexion) instanziiert werden, wenn er einen Standardkonstruktor hat. Außerdem muss die
new()
generische Typbeschränkung angegeben werden:void Construct<T>() where T : new() { var t = new T(); ... }
Das Aufrufen dieser Methode unter Verwendung eines Typs als generisches Typargument ohne Standardkonstruktor führt zu einem Compilerfehler.
quelle