2009-09-23 7 views
10

Il seguente codice compila, ma non riesce con un NullReferenceException:C compilation # dizionario initializer incoerenza

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

static void Main(string[] args) 
{ 
    var x = new Test 
    { 
     Dictionary = // fails 
     { 
      { "key", "value" }, { "key2", "value2" } 
     } 
    }; 
} 

Se si sostituisce la linea indicata 'riesce' con la seguente, funziona (come previsto):

Dictionary = new Dictionary<string, string> 

C'è qualche proposito alla sintassi fallita - può essere usato con successo in qualche altro caso? O è una svista nel compilatore?

risposta

32

No, non è un errore ... è un difetto nella vostra comprensione della sintassi di inizializzazione :)

L'idea del

Dictionary = { ... } 

è per i casi in cui il chiamante ha lettura accesso a una proprietà della raccolta, ma non scrivere l'accesso. In altre parole, situazioni come questa:

class Test 
{ 
    private readonly Dictionary<string, string> dictionary 
     = new Dictionary<string, string>(); 
    public Dictionary<string, string> Dictionary { get { return dictionary; } } 
} 

Fondamentalmente finisce con le chiamate a Aggiungi, ma senza creare prima una nuova raccolta. Quindi, questo codice:

Test test = new Test { Dictionary = { { "a", "b"}, {"c", "d" } }; 

è equivalente a:

Test tmp = new Test(); 
Dictionary<string, string> tmpDictionary = tmp.Dictionary; 
tmpDictionary.Add("a", "b"); 
tmpDictionary.Add("c", "d"); 
Test test = tmp; 

Un buon esempio di dove questo è utile è con la raccolta Controls per un'interfaccia utente. Si può fare questo:

Form form = new Form 
{ 
    Controls = 
    { 
     new Button { Text = "Hi" }, 
     new TextBox { Text = "There" } 
    } 
}; 

, ma non si poteva impostare la proprietà Controls, perché è di sola lettura.

+0

Così è usato per aggiungere elementi a un dizionario creato dal costruttore - avrei dovuto rendermene conto. Ma è un uso bizzarro dell'operatore di equals, poiché l'effetto è di aggiungere a qualsiasi cosa sia già nel dizionario (il costruttore potrebbe aver aggiunto prima gli elementi). –

+0

Sort of, yes ... ma allo stesso tempo è usato per impostare i valori iniziali nella collezione, quindi si adatta in questo modo. –

+0

Giusto. Il 'new' mancante avrebbe dovuto essere una bandiera rossa .. ma non avendo mai usato questa sintassi, ho preso l'operatore di uguali troppo alla lettera. –

0

Non riesce con un'eccezione di riferimento null poiché è stata dichiarata una variabile (Dizionario) non controllata, quindi è nulla.

Quando si tenta di aggiungere le voci utilizzando la sintassi di inizializzazione, si sta tentando di scrivere dati in un oggetto nullo.

Quando si sostituisce la riga con un "= nuovo dizionario ...", si sta creando un nuovo oggetto per il riferimento del dizionario e quindi è possibile aggiungere le voci correttamente.

(Nell'esempio di Jon Skeet, Controls deve essere già stato creato dal modulo, quindi funziona bene)

+0

Sì, certo. La mia domanda era: perché consentire questa sintassi? –

+0

Abbastanza giusto.Jon ha risposto alla tua domanda quindi ho pensato di inserire il motivo nel caso in cui non capissi il fallimento. –

4

È comunque possibile utilizzare la sintassi che si desidera in un costruttore:

Dictionary<string, string> dictionary = new Dictionary<string, string> 
      { 
       {"a", "b"}, 
       {"c", "d"} 
      };