2009-05-14 6 views
27

Ich frage mich, was ist der bevorzugte Weg, um ein neues Objekt in C# zu konstruieren?Was ist die bevorzugte Methode zum Erstellen von Objekten in C#? Konstruktorparameter oder Eigenschaften?

eine Person-Klasse nehmen:

public class Person 
{ 
    private string name; 
    private int age; 

    //Omitted.. 
} 

Sollte ich es schaffen zu verwenden:

New Person("name", 24); 

oder

New Person() { Name = "name", Age = 24 }; 

Ist es oder ein gut ist es nur eine Frage des Geschmacks Grund, einen über den anderen zu benutzen?

Ich kann mir vorstellen, dass man die erforderlichen Felder in den Konstruktor- und optionalen Feldern nicht nur als Konstruktorparameter verwenden sollte, sondern auch mithilfe von Eigenschaften.

Bin ich richtig darin?

+2

Dies ist effektiv die C# -Version von http://StackOverflow.com/Questions/830657 –

Antwort

39

Der bevorzugte Weg hängt von Ihrem Entwurf ab.

Konstruktoreigenschaften sind für Objekte, die Ihr Objekt benötigt, um korrekt konstruiert zu sein. Das heißt, alle Eigenschaften, die das Objekt haben sollte, um initialisiert zu werden, müssen im Konstruktor sein (normalerweise möchten Sie ein teilweise initialisiertes Objekt nicht, nachdem der Konstruktor aufgerufen wurde, es sei denn, Sie erstellen ein Factory- oder Builder-Muster und das Konstruktor ist von allen außer dem Hersteller/Hersteller ausgeblendet).

Property-Initializer eignen sich am besten für die zusätzliche Konfiguration nach einem Konstruktor, der für Ihren speziellen Anwendungsfall erforderlich ist, aber nicht erforderlich ist, damit das Objekt als initialisiert betrachtet wird.

Zum Beispiel könnten Sie ein Objekt haben, das eine Person darstellt. Eine Person benötigt einen Namen und ein Alter, um initialisiert zu werden, aber die Adresse, unter der sie leben, ist eine optionale Konfiguration.Der Name und das Alter sind also Konstruktorparameter, und die Adresse ist eine Lese-/Schreibeigenschaft.

Person johnDoe = new Person("John Doe", 24) { Address = "42 Adams Street" }; 
+0

das ist eine sehr nette Begründung, die hilft zu erkennen, wann was anzuwenden ist. Vielen Dank! – Peterdk

+0

Ich empfehle Marc Gravell's Antwort auch (http://stackoverflow.com/a/863064/23234), die einige alternative Szenarien bietet, die echte Anwendungen betrachten, wo der idealere Gesichtspunkt, den ich vorgestellt habe, aufgrund anderer Beschränkungen nicht relevant ist. –

2

Der zweite Weg ist nur syntaktischer Zucker für die Eigenschaften manuell einstellen:

Person p = new Person(); 
p.Name = "name"; 
p.Age = 24; 

Sie sind auch nicht auf den Konstruktor abhängig, die nicht alle Eigenschaften, die Sie festlegen möchten initialisieren kann.

Wenn Ihre Klasse über einen Konstruktor verfügt, der diese beiden Parameter benötigt, können Sie diesen Konstruktor nicht explizit aufrufen.

12

Es hängt wirklich vom Szenario ab. Der Eigenschaftsansatz bietet eine Menge Komfort, da Sie die Zuweisungen im Konstruktor nicht duplizieren müssen. Außerdem sind die meisten Datenbindungsszenarien in der Lage, neue Objekte zu erstellen, für die sie normalerweise den parameterlosen Konstruktor verwenden, was einen großen Vorteil darstellt.

Für unveränderliche Typen ist jedoch der Konstruktoransatz die einzig sinnvolle Option. Interessanterweise (vielleicht) erlauben die genannten/optionalen Parameter in C# 4.0 etwas, das Objektinitiatoren für unveränderliche Typen ähnlich ist - see here.

Der Konstruktor-Ansatz ist auch sehr beliebt für Inversion of Control-Frameworks, da es deutlich ankündigt, was diese Klasse benötigt, um zu funktionieren.

Möglicherweise müssen Sie mischen und übereinstimmen, aber in der Regel mehr Eigenschaftsstil als Konstruktor-Stil.

+2

Ja - Readonly-Felder können nur durch Konstruktor-Code festgelegt werden. – Dario

5

Wenn Sie die Werte im Konstruktor festlegen, werden diese Eigenschaften obligatorisch. Dies bedeutet, dass Sie keine neue Instanz erstellen können, ohne diese Eigenschaften zu ändern. In einigen Situationen ist dies vorzuziehen, in anderen Situationen ist dies nicht vorzuziehen.

+0

Das ist richtig, obwohl für Strukturen natürlich die Einstellung nicht zwingend erforderlich ist. – Noldorin

+0

Tatsächlich, aber das liegt daran, dass eine Struktur ein Werttyp ist und immer einen (Standard) Wert hat, auch wenn sie nicht initialisiert ist. –

0

Meine wichtigsten Überlegungen zu dieser Frage sind 1) Wie viele Daten wird die Instanziierungseinheit haben, wenn das Objekt instanziiert wird und 2) Wie gekapselt muss die Klasse sein? Wenn die Eigenschaften einmal nicht geändert werden sollten (zumindest aufgrund externer Entitäten), würde ich den Konstruktor verwenden, da der Konstruktor alle schreibgeschützten Eigenschaften sowie alle Lese-/Schreibeigenschaften festlegen kann.

Denken Sie auch daran, dass Ihr Konstruktor wie jede andere Methode überlastet werden kann, sodass Sie eine Reihe von Möglichkeiten zum Initialisieren dieser Eigenschaften einrichten können.

Im Allgemeinen verwende ich Konstruktoren, aber manchmal stelle ich die Eigenschaften manuell ein. Verwenden Sie das richtige Werkzeug für das richtige Problem.

7

Ich arbeite immer auf der Grundlage, dass Sie Werte an einen Konstruktor übergeben sollten, die für das Objekt in einem gültigen Zustand erforderlich sind.

In Ihrem Beispiel könnte man sagen, dass eine neue Person nicht ohne Alter existieren kann, so dass sie dem Konstruktor übergeben werden sollte.

Wenn Sie auf der Grundlage arbeiten, dass ein Objekt eine reale Arbeitsentität modellieren soll, bestimmt dies das erforderliche Minimum, um ein Objekt gültig zu machen - ob Sie diese als Standardwerte festlegen oder Werte über den Konstruktor übergeben.

+1

+1: Objekte sollten nach der Konstruktion und nach jedem Methodenaufruf immer in einem gültigen Zustand belassen werden, so dass die Methoden nicht den Zustand ihres eigenen Objekts vor dem Ausführen validieren müssen, sondern nur ihre Argumente. – palm3D

2

Meiner Meinung nach sollten Sie zuerst entscheiden, was eine Person zu einer Person macht. Was sind die Eigenschaften der Person, damit ein Personenobjekt korrekt instanziiert wird? Was sind die Mindestanforderungen für eine Person?

Es sollte immer einen Konstruktor mit den Mindestanforderungen geben.

Ich würde nur Objektinitialisierer für Typen verwenden, für die keine Eigenschaften instanziiert werden müssen. Daher der Standardkonstruktor.

Ich weiß, dass Objektinitialisierer sehr praktisch sind. Andere Mechanismen erfordern möglicherweise auch einen leeren Konstruktor im Objekt.

Aber ich denke nicht, dass es sehr sinnvoll ist, dass Sie eine Person ohne Namen erstellen können.

4

Ein paar Gedanken:

  1. Sie müssen öffentliche Eigenschaften Objektinitialisierer verwenden. Wenn also etwas nicht angezeigt werden soll, müssen Sie sie mit dem Konstruktorparameter initialisieren.

  2. Wenn Sie IL überprüfen, werden Sie feststellen, dass der Objektinitialisierer nicht "atomar" ist. Wenn Sie Code wie diesen schreiben (nicht, dass ich empfehlen, nur ein Beispiel):

    using (p = New Person() {Name = GetName(), Age = GetAge()}) 
    { 
        //blah, blah 
    } 
    

    Wenn es in GetAge() eine Ausnahme ist, erhalten Sie eine Instanz von Person in einem beschädigten Zustand erstellen. Schlimmer noch, Sie können den Anwendungsbereich nicht eingeben, und diese Instanz wird nicht so angeordnet, wie Sie es sich vorstellen.

+0

Ich mag, dass Sie darauf hingewiesen haben, dass es nicht atomar ist. Offensichtlich, wenn Sie es sehen, und ich glaube nicht, dass ich Code schreiben würde, wie Sie es geschrieben haben, aber wenn ich den Code von jemand anderem gelesen hätte, hätte ich das wahrscheinlich nicht bemerkt. –

0

Für Einstellungen die Eigenschaften manuell, müssten sie öffentlich erklärt werden, und Sie möchten möglicherweise die Klassenmitglieder privat sein. In diesem Fall ist der Konstruktor der Weg zu gehen oder Methoden zu schreiben, um sie zu erhalten/setzen oder einen Accessor zu verwenden.

0

Ich bevorzuge einen sehr einfachen Konstruktor mit Eigenschaft Intialiser. Ich finde es führt zu mehr expliziten Code. Die einzigen Daten, die ich an den Konstruktor übergeben würde, sind Informationen, die der Benutzer meiner Klasse nicht ändern soll, sobald die Klasse erstellt wurde.

0

Das eigentliche Problem tritt auf, wenn Sie das Objekt durch Ebenen/Ebenen übergeben. Zum Beispiel erstellen Sie ein Personenobjekt und durchlaufen einen Webservice. Der Webservice bei somepoint versucht zu deserialisieren und versucht zu instanziieren und dann könnte es zu einem Fehler kommen, wenn ein Parameter für Konstruktoren benötigt wird! als Webservices erstellt zuerst ein Objekt und weist dann Werte zu.

Also würde ich einen parameterlosen Konstruktor bevorzugen, wenn es ein Datamodell (POCO Art von) ist, die Ebenen durchlaufen muss.

Aus anderen Gründen ist contructor Parameter der beste Weg (für Pflichtfelder). Insbesondere, wenn die Klasse als Iterface für externe Objekte oder Baugruppen bereitgestellt wird.