2013-10-02 11 views
52

Angenommen ich habe eine Album Klasse:C#: Daten zu Eigenschaften über Konstruktor zuweisen vs. Instanziieren

public class Album 
{ 
    public string Name {get; set;} 
    public string Artist {get; set;} 
    public int Year {get; set;} 

    public Album() 
    { } 

    public Album(string name, string artist, int year) 
    { 
     this.Name = name; 
     this.Artist = artist; 
     this.Year = year; 
    } 
} 

Wenn ich will Typ auf ein Objekt der Daten zuzuordnen Album, was ist der Unterschied zwischen den nächsten 2 Ansätzen :

Via Constructor

var albumData = new Album("Albumius", "Artistus", 2013); 

oder wenn instantia ting

var albumData = new Album 
        { 
         Name = "Albumius", 
         Artist = "Artistus", 
         Year = 2013 
        }; 
+7

möglich Duplikat von [Was ist der Unterschied zwischen einem Objektinitialisierer und einem Konstruktor?] (Http: // stackoverflow.com/questions/740658/whats-the-difference-zwischen-einem-objekt-initializer-and-a-constructor) –

+0

für eine im Konstruktor Sie könnten einen Wert zuweisen, um eine private Member-Variable mit Objekt-Initialisierer nur gehen Sie mit öffentlichen Eigenschaften – terrybozzio

+0

Ihr Konstruktor zwingt Sie, Name, Künstler & Jahr zu übergeben. Sie sind optional für Ihren Objektinitiator. – Carra

Antwort

83

Beide Ansätze rufen einen Konstruktor auf, sie rufen nur verschiedene Konstrukte auf. Dieser Code:

var albumData = new Album 
       { 
        Name = "Albumius", 
        Artist = "Artistus", 
        Year = 2013 
       }; 

ist syntaktische Abkürzung für diese entsprechende Code:

var albumData = new Album(); 
albumData.Name = "Albumius"; 
albumData.Artist = "Artistus"; 
albumData.Year = 2013; 

Die beiden identisch nach der Kompilierung sind. Also, wenn der parameterlosen Konstruktor nicht öffentlich ist:

public Album() { } 

dann würden Sie nicht in der Lage sein, die Objektinitialisierer verwenden überhaupt sowieso. Die Hauptfrage ist also nicht, welche zu verwenden, wenn das Objekt initialisiert wird, sondern welche Konstruktoren das Objekt an erster Stelle exponiert. Wenn das Objekt zwei Konstruktoren (wie die in Ihrem Beispiel) verfügbar macht, dann kann davon ausgegangen werden, dass beide Möglichkeiten für die Konstruktion eines Objekts gleichermaßen gültig sind.

Manchmal stellen Objekte keine parameterlosen Konstruktoren aus, weil sie bestimmte Werte für die Konstruktion benötigen. In solchen Fällen können Sie die Syntax des Initialisierers dennoch für andere Werte verwenden. Angenommen, Sie diese Konstrukteure auf dem Objekt haben:

private Album() { } 
public Album(string name) 
{ 
    this.Name = name; 
} 

Da der parameterlosen Konstruktor privat ist, können Sie nicht so verwenden können. Aber man kann die andere verwenden und nach wie vor Verwendung der initializer Syntax machen:

var albumData = new Album("Albumius") 
       { 
        Artist = "Artistus", 
        Year = 2013 
       }; 

Die nach der Kompilierung Ergebnis wäre dann identisch sein:

var albumData = new Album("Albumius"); 
albumData.Artist = "Artistus"; 
albumData.Year = 2013; 
+1

Über die ersten beiden Beispiele; Es mag interessant sein, dass diese nach der Kompilierung nicht identisch sind, wenn der Verweis auf das erzeugte Objekt in einem Feld oder global statt einer lokalen Variable gespeichert wird. Wenn eine Ausnahme in einem Eigenschaften-Setter auftritt, wird das Feld in einem Fall festgelegt und in dem anderen nicht. Diese Art der Sache kann im Umgang mit Einwegobjekten und CA2000 wichtig sein. –

10

Zweiter Ansatz ist object initializer in C#

Objektinitialisierer können Sie Werte an allen zugänglichen Bereichen oder Eigenschaften eines Objekts zum Zeitpunkt der Erstellung zuweisen , ohne explizit einen Konstruktor mit aufzurufen.

Der erste Ansatz

var albumData = new Album("Albumius", "Artistus", 2013); 

nennt explizit den Konstruktor, während im zweiten Ansatz Konstruktoraufruf implizit ist. Mit dem Objektinitialisierer können Sie auch einige Eigenschaften weglassen. Wie:

var albumData = new Album 
     { 
      Name = "Albumius", 
     }; 

Objektinitialisierer übersetzen würde in so etwas wie:

var albumData; 
var temp = new Album(); 
temp.Name = "Albumius"; 
temp.Artist = "Artistus"; 
temp.Year = 2013; 
albumData = temp; 

Warum verwendet er ein temporäres Objekt (im Debug-Modus) beantwortet here von Jon Skeet.

Was Vorteile für beide Ansätze betrifft, IMO, wäre Objektinitialisierung einfacher zu verwenden, besonders wenn Sie nicht alle Felder initialisieren möchten. Was den Leistungsunterschied anbetrifft, glaube ich nicht, dass es irgendwelche gibt, da der Objektinitialisierer den Parameter weniger Konstruktor aufruft und dann die Eigenschaften zuweist. Selbst wenn es einen Leistungsunterschied geben sollte, sollte es vernachlässigbar sein.

+2

Ich denke, ein Teil der Frage ist - "Ist es eine gute Sache, Konstrukteure zu umgehen?". Gibt es Vorteile (Flexibilität) oder Nachteile (Umgehung der Konstruktorlogik, Geschwindigkeit vielleicht?) – guymid

+3

Der Konstruktor wird nicht umgangen. Der parameterlose Konstruktor wird verwendet. – Ralf

+0

Ja naja, das wollte ich eigentlich eigentlich meinen ... Gibt es einen Vorteil gegenüber dem anderen? Gibt es eine bessere Leistung als die andere? So etwas (Cons und Pro) – VasileF

17

Objektinitialisierer kühl sind, weil sie ermöglichen es Ihnen, richten Sie eine Klasse inline ein. Der Nachteil ist, dass Ihre Klasse nicht unveränderbar sein kann. Bedenken Sie:

public class Album 
{ 
    // Note that we make the setter 'private' 
    public string Name { get; private set; } 
    public string Artist { get; private set; } 
    public int Year { get; private set; } 

    public Album(string name, string artist, int year) 
    { 
     this.Name = name; 
     this.Artist = artist; 
     this.Year = year; 
    } 
} 

Wenn die Klasse auf diese Weise definiert ist, bedeutet es, dass es nicht wirklich eine einfache Möglichkeit, den Inhalt der Klasse zu ändern, nachdem es konstruiert wurde. Unveränderlichkeit hat Vorteile. Wenn etwas unveränderlich ist, ist es VIEL einfacher festzustellen, dass es korrekt ist. Wenn es nach der Konstruktion nicht geändert werden kann, gibt es keine Möglichkeit, dass es jemals "falsch" ist (sobald Sie festgestellt haben, dass seine Struktur korrekt ist).

new { 
    Name = "Some Name", 
    Artist = "Some Artist", 
    Year = 1994 
}; 

die Compiler eine unveränderliche Klasse automatisch erstellen (das heißt, können anonyme Klassen nicht nach dem Bau geändert werden), weil Unveränderlichkeit nur, dass nützlich ist: Wenn Sie anonyme Klassen, wie zum Beispiel erstellen. Die meisten C++/Java-Styleguides ermutigen aus diesem Grund oft, Member const (C++) oder final (Java) zu machen. Größere Anwendungen sind einfach zu überprüfen, wenn weniger bewegliche Teile vorhanden sind.

Das alles gesagt, gibt es Situationen, wenn Sie die Struktur Ihrer Klasse schnell ändern können. Lassen Sie uns sagen, dass ich ein Werkzeug, das ich einrichten möchten:

public void Configure(ConfigurationSetup setup); 

und ich habe eine Klasse, die eine Anzahl von Mitgliedern, zB:

class ConfigurationSetup { 
    public String Name { get; set; } 
    public String Location { get; set; } 
    public Int32 Size { get; set; } 
    public DateTime Time { get; set; } 

    // ... and some other configuration stuff... 
} 

Mit Objektinitialisierer Syntax ist nützlich, wenn ich will zu konfigurieren einige Kombination von Eigenschaften, aber nicht notwendig alle von ihnen auf einmal. Zum Beispiel, wenn ich die Name und Location nur konfigurieren möge, kann ich nur tun:

ConfigurationSetup setup = new ConfigurationSetup { 
    Name = "Some Name", 
    Location = "San Jose" 
}; 

und dies ermöglicht es mir eine Kombination einzurichten, ohne einen neuen Konstruktor für jede möglicherweise Permutation definieren zu müssen.

Im Großen und Ganzen würde ich argumentieren, dass die Unveränderbarkeit Ihrer Klassen Ihnen auf lange Sicht viel Entwicklungszeit sparen wird, aber die Syntax des Objektinitialisierers vereinfacht die Einrichtung bestimmter Konfigurationspermutationen.

+0

@siercodesalot, Vielen Dank für Ihre Antwort. Aber ich denke nicht, nur einige der Eigenschaften im Objektinitialisierer anzugeben, ist das beste Argument. Da Sie einfach im Konstruktor Standardwerte verwenden und die Angabe einer Eigenschaft überspringen können. – VasileF

+0

Werfen Sie einen Blick auf 'AppDomainSetup' (http://msdn.microsoft.com/en-us/library/system.appdomainsetup.aspx), das zum Konfigurieren neuer Anwendungsdomänen verwendet wird. Möchten Sie wirklich einen Konstruktor haben, der 20 verschiedene Eigenschaften hat - besonders wenn Sie nur ein oder zwei definieren wollen? Zweitens funktionieren Standardwerte nicht wirklich, wenn Sie Eigenschaften nur am Ende der Konstruktorliste (aber nicht am Anfang) konfigurieren möchten. – sircodesalot

+0

Versteh mich nicht falsch, ich bin mit Objektinitialisierer sehr vertraut und es ist nützlich und schnell. Ich wollte wissen, ob es einen Unterschied wie Leistung oder Best Practice oder Nachteile/Vorteile gibt. Sie können im Konstruktor den zu definierenden Parameter explizit angeben.Angenommen, ich hätte alle Konstruktor-Parameter mit dem angegebenen Standardwert, könnte ich sie so in der Liste neu anordnen, wie ich möchte: 'var album = new Album (Jahr: 2013, Artist:" Artistus "). es ist unbequemere Arbeit oder du meintest etwas anderes mit Ende/Anfang? – VasileF

Verwandte Themen