7

Ich habe diesen einfachen Code:Warum darf ich Eigenschaften ändern, die nur mit Objektinitialisierern gelesen werden?

public static void Main(String[] args) 
{ 
    Data data = new Data { List = { "1", "2", "3", "4" } }; 
    foreach (var str in data.List) 
     Console.WriteLine(str); 
    Console.ReadLine(); 
} 

public class Data 
{ 
    private List<String> _List = new List<String>(); 
    public List<String> List 
    { 
     get { return _List; } 
    } 
    public Data() { } 
} 

Also, wenn ich eine Datenklasse zu schaffen:

Data data = new Data { List = { "1", "2", "3", "4" } }; 

Die Liste mit Strings "1", "2", "3" gefüllt wurde, "4" auch wenn es keine set hatte.

Warum passiert das?

+4

Sie fügen Elemente zu 'List string2' hinzu und dann lesen Sie' List string1' macht für mich keinen Sinn. – kevintjuh93

+0

tatsächlich. Aber string2 ist nach dem Hinzufügen von Elementen sehr klein. – Asbrand

+2

Woher weißt du das? Sie überprüfen 'List string2' nicht irgendwo in Ihrem Code. – kevintjuh93

Antwort

11

Ihre Objektinitialisierer (mit Auflistungsinitialisierer für List)

Data data = new Data { List = { "1", "2", "3", "4" } }; 

in den folgenden gedreht wird:

var tmp = new Data(); 
tmp.List.Add("1"); 
tmp.List.Add("2"); 
tmp.List.Add("3"); 
tmp.List.Add("4"); 
Data data = tmp; 

es Blick auf diese Weise es sollte klar sein, warum Sie sind in der Tat, Hinzufügen zu string1 und nicht zu string2: tmp.Listgibtstring1 zurück. Sie ordnen der Eigenschaft niemals nur die Sammlung zu, die zurückgegeben wird. Also solltest du hier auf den Getter schauen, nicht auf den Setter.

Tim ist jedoch absolut richtig, da eine so definierte Eigenschaft keinen Sinn ergibt. Dies verletzt das Prinzip der geringsten Überraschung und für Benutzer dieser Klasse ist es überhaupt nicht ersichtlich, was mit dem Setter dort passiert. Tu solche Dinge einfach nicht.

+1

Sicher, es ist kein Code für echte Aufgabe, ich will nur wissen, wie die Dinge funktionieren =) – Asbrand

+2

@Asbrand: Wenn Sie daran interessiert sind, wie die Dinge funktionieren, empfehle ich Ihnen, [ILSpy] (http://ilspy.net/) und herunterzuladen stoße in den Compiler-Ausgang. Oder lesen Sie die C# Spezifikation. Beide sind natürlich etwas gewöhnungsbedürftig, aber als Lernressourcen sind sie von unschätzbarem Wert. – Joey

+0

@Joey: statt eines Decompilers würde ich http://referencesource.microsoft.com/ verwenden. Beachten Sie auch, dass ich meine Antwort inzwischen gelöscht habe. –

4

Das ist, wie Auflistungsinitialisierer intern arbeiten:

Data data = new Data { List = { "1", "2", "3", "4" } }; 

Es ist im Grunde gleich

Data _d = new Data(); 
_d.List.Add("1"); 
_d.List.Add("2"); 
_d.List.Add("3"); 
_d.List.Add("4"); 
Data data = _d; 

Und _d.List verwendet string1 in Getter.

[*] Mehr Details in C# Spezifikation $ 7.6.10.3 Collection initializers


Code ändern zu diesem:

Data data = new Data { List = new List<string>{ "1", "2", "3", "4" } }; 

Und string1 leer sein wird und string2 werden vier Elemente haben.

+1

* ändern Sie den Code * Teil wird die Ausnahme ausgelöst 'Eigenschaft oder Indexer 'Program.Data.List' kann nicht zugewiesen werden - es ist nur lesbar' und das ist eigentlich der Grund der Verwirrung, warum die Eigenschaft ohne Setter sieht wie einstellbar an erster Stelle . – Sinatr

+1

@Sinatr, Tim Schmelter hat die Frage erheblich bearbeitet! Überprüfen Sie den Bearbeitungsverlauf. Ich sollte zustimmen, 2. Beispiel funktioniert nach der Bearbeitung nicht – ASh