2011-01-23 16 views
6

dire che ho una classe che ha una proprietà che è un dizionario < string, bool >, utilizzando un inizializzatore di oggetto posso usare questa sintassi (che a mio avviso sembra abbastanza pulito):inizializzatori di oggetti covarianti?

new MyClass() 
{ 
    Table = { {"test",true},{"test",false} } 
} 

tuttavia, al di fuori dell'inizializzatore Non riesco a farlo:

this.Table = { {"test",true},{"test",false} }; 

Perché gli inizializzatori sono un caso speciale? Potrei azzardare un'ipotesi che abbia qualcosa a che fare con i requisiti LINQ, covarianza o quant'altro, ma sembra un po 'incongruente non essere in grado di usare quel tipo di inizializzatore ovunque ...

+0

domanda interessante. –

+0

Penso che il fatto che l'errore del compilatore sia "espressione attesa" è un grande indizio. Nel secondo esempio, la sintassi non indica un'espressione come ci si aspetterebbe di solito non esiste un operatore 'new'. Sospetto che il primo esempio funzioni in quanto è un caso speciale e il compilatore è più rilassato riguardo a ciò che costituisce un'espressione sintatticamente. Il vantaggio delle regole rilassate è la sintassi terser che è altamente auspicabile per il contesto della sintassi di inizializzazione dell'oggetto, altrimenti apparirebbe fugamente. –

risposta

0

Considerando la sintassi si genera un NullReferenceException in fase di esecuzione - sei sicuro di poterlo usare?

public class Test 
{ 
    public Dictionary<string, bool> Table {get; set;} 
} 

public void TestMethod() 
{ 
    Test t = new Test { Table = { {"test", false} } }; //NullReferenceException 
} 

Questo compila il seguente (via riflettore):

Test <>g__initLocal3 = new Test(); 
<>g__initLocal3.Table.Add("test", 0.0M); 

Come si può vedere, Table non è inizializzata, producendo così un NullReferenceException in fase di esecuzione.

Se si crea il dizionario nel ctor della Test, l'inizializzatore di classe produce una cascata di Add dichiarazioni, che è zucchero sintattico nel inizializzatore (per IEnumerable s).

Questo probabilmente non è stato introdotto per il codice normale a causa di effetti collaterali indesiderati che non possiamo vedere o immaginare. Eric Lippert potrebbe essere in grado di dare una mano in quanto probabilmente ha più informazioni sull'argomento in questione.

+2

sì, lo so, ma non la stessa sintassi esatta – Homde

+3

ma non sta chiedendo perché devi fornire il 'nuovo dizionario ' di fronte ad esso. –

+1

Se si crea il dizionario nella funzione di costruzione Test o altrove, non genera l'eccezione. –

2

Questa limitazione è molto più antica di LINQ. Anche in C puoi scrivere

int numbers[5] = {1, 2, 3, 4, 5}; 

ma non è possibile utilizzare questa sintassi per assegnare valori all'array.

La mia ipotesi sul motivo di questo in C# è che di solito non si dovrebbe usare lo stesso riferimento per due oggetti diversi. Se è necessario assegnare una nuova raccolta a un riferimento esistente, molto probabilmente non è stato progettato molto bene il proprio codice e si può inizializzare la raccolta alla definizione oppure utilizzare due riferimenti separati anziché uno.

+0

Questo non ha nulla a che fare con Linq per quanto posso vedere. E come puoi usare lo stesso riferimento per due oggetti diversi? –

+0

@chibacity: questo è quello che ho detto. mko ha pensato che questo abbia qualcosa a che fare con LINQ, e credo che non sia così. E puoi usare lo stesso riferimento per due oggetti se assegni ad esso una collezione e poi assegna un altro, come questo: 'col = nuovo Dizionario (...)'. Penso che questo faccia apparire il codice peggiore ed è meglio usare un nuovo riferimento. –

+0

@Ilya vedo. E 'solo confuso portare l'angolo C. In. C# ha anche inizializzatori di array, ma quanto sopra non è un esempio di inizializzatore di array, è un inizializzatore di raccolta. Ben diversa. –

11

La domanda è alquanto confusa, poiché la domanda non ha nulla a che fare con LINQ, niente a che fare con la varianza generica e presenta un inizializzatore di raccolta, nonché un inizializzatore di oggetti. La vera domanda è, per quanto posso dire "perché non è legale utilizzare un inizializzatore raccolta al di fuori di un'espressione creazione di oggetti?"

Il principio costruttivo rilevante è che, in generale, vogliamo operazioni che creare e inizializzare oggetti per avere la parola "nuovo" in loro da qualche parte come un segnale per il lettore che c'è una creazione di un oggetto che accade qui. (Sì, ci sono alcune eccezioni a questa regola in C#. Come esercizio per il lettore, vedi se riesci a nominarli tutti.)

Fare le cose a modo tuo rende più difficile ragionare sul codice. Veloce, cosa fa questo?

d = new List<int>() { 10, 20, 30 }; 
d = { 40, 50, 60 }; 

Ha la seconda linea accodare 40, 50, 60 alla lista già esistente?O sostituisce la vecchia lista con una nuova? Non c'è "nuovo" lì dentro, così il lettore si aspetta che sia stato creato un nuovo oggetto?

Quando si dice

q = new Whatever() { MyList = { 40, 50, 60 } }; 

che non crea un nuovo elenco; aggiunge 40, 50, 60 a un elenco esistente assegnato dal costruttore. La sintassi proposta è quindi ambigua e confusa sul fatto che venga creato o meno un nuovo elenco.

La funzione proposta è confusa e non necessaria, pertanto è improbabile che venga implementata in tempi brevi.

+0

Hai ragione, inizialmente pensavo che effettivamente creato una nuova collezione, non solo impostarne i valori. Quindi è sicuramente fonte di confusione. Era solo un po 'curioso del diverso comportamento, grazie per averlo chiarito – Homde

+0

-1 Perché possiamo inizializzare gli array in questo modo: int [] array = {1, 2, 4}; Penso che gli sviluppatori di C# non stessero pensando alla parola chiave "nuova" che invia segnali al lettore. Quindi, non puoi dire PERCHÉ lo hanno fatto * davvero *. –

+6

@lazyberezovsky: Questo è uno dei casi speciali che ho menzionato. Si noti che * solo * funziona nell'inizializzatore di una dichiarazione. Per quanto riguarda il motivo per cui il comitato di progettazione C * * ha davvero * fatto o non fatto qualcosa, sospetto di avere * un po '* più approfondimento in proposito di te, poiché ho le loro note di progettazione e ho discusso la progettazione linguistica con almeno due dei designer originali da sei a otto ore a settimana negli ultimi cinque anni. –

Problemi correlati