7

Ho questo semplice codice:Perché sono autorizzato a modificare le proprietà che sono di sola lettura con gli inizializzatori dell'oggetto?

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() { } 
} 

così quando sono la creazione di una classe di dati:

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

L'elenco è stato compilato con le stringhe "1", "2", "3", "4" anche se non aveva set.

Perché sta succedendo?

+4

Si stanno aggiungendo elementi a 'List string2' e quindi si sta leggendo' List string1' non ha senso per me. – kevintjuh93

+0

davvero. Ma List string2 è epmty dopo aver aggiunto elementi – Asbrand

+2

Come fai a saperlo ?? Non stai controllando 'List string2' in nessun punto del tuo codice. – kevintjuh93

risposta

11

vostro inizializzazione degli oggetti (con la collezione di inizializzazione per List)

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

ottiene trasformato in quanto segue:

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

Guardando in questo modo dovrebbe essere chiaro il motivo per cui si è, infatti, aggiungendo a string1 e non a string2: tmp.Listrestituiscestring1. Non si assegna mai alla proprietà, si inizializza semplicemente la raccolta restituita. Quindi dovresti guardare il getter qui, non il setter.

Tuttavia, Tim è assolutamente corretto in quanto una proprietà definita in questo modo non ha alcun senso. Ciò viola il principio di minima sorpresa e agli utenti di quella classe non è del tutto evidente ciò che accade al setter lì. Basta non fare cose del genere.

+1

Certo, non è il codice per il vero compito, voglio solo sapere come funzionano le cose =) – Asbrand

+2

@Asbrand: se ti interessa come funzionano le cose ti consiglio di scaricare [ILSpy] (http://ilspy.net/) e colpire l'output del compilatore. Oppure leggi la specifica C#. Entrambi si prendono un po 'per abituarsi, ovviamente, ma come risorse di apprendimento sono inestimabili. – Joey

+0

@Joey: al posto di un decompilatore vorrei usare http://referencesource.microsoft.com/ Nota anche che ho eliminato la mia risposta nel frattempo. –

4

che è come inizializzatori raccolta lavorano internamente:

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

E 'sostanzialmente uguale alla

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

E _d.List usa string1 in getter.

[*] Maggiori dettagli nelle specifiche C# $ 7.6.10.3 Collection initializers


modificare il codice per questo:

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

E string1 sarà vuota e string2 avranno quattro voci.

+1

* modifica il codice * la parte genererà un'eccezione 'La proprietà o l'indicizzatore 'Program.Data.List' non può essere assegnato a - è di sola lettura 'e questo è in realtà il motivo di confusione perché la proprietà senza setter sembra settabile al primo posto . – Sinatr

+1

@Sinatr, Tim Schmelter ha modificato in modo significativo la domanda! controlla la cronologia delle modifiche. Dovrei essere d'accordo, il secondo esempio non funziona dopo la modifica – ASh

Problemi correlati