2009-09-23 5 views
10

Der folgende Code kompiliert, aber nicht mit einem NullReferenceException:C# Wörterbuch initializer Kompilation Inkonsistenz

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

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

Wenn Sie die Zeile markiert ersetzen 'versagt' mit dem folgenden, es funktioniert (wie erwartet):

Dictionary = new Dictionary<string, string> 

Gibt es einen Zweck für die fehlerhafte Syntax - kann sie in einem anderen Fall erfolgreich verwendet werden? Oder ist das ein Versehen im Compiler?

Antwort

32

Nein, es ist kein Fehler ... es ist ein Fehler in Ihrem Verständnis der Initialisierung Syntax :)

Die Idee der

Dictionary = { ... } 

ist für Fälle, in denen der Anrufer hat lesen Zugang zu einer Sammlung Eigenschaft, aber nicht schreiben Zugriff. Mit anderen Worten, Situationen wie folgt:

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

Im Grunde wird es am Ende Aufrufe von Add, aber ohne eine neue Sammlung zuerst erstellen. Also dieser Code:

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

entspricht:

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

Ein gutes Beispiel, wo dies nützlich ist mit der Controls Sammlung für eine UI. Sie können dies tun:

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

aber man konnte nicht wirklich gesetzt die Controls Eigenschaft, weil es nur gelesen wird.

+0

So Es wird verwendet, um Elemente zu einem Wörterbuch hinzuzufügen, das vom Konstruktor erstellt wurde - das hätte ich erkennen sollen. Aber es ist eine seltsame Verwendung des Gleichheitsoperators, da der Effekt darin besteht, zu dem zu addieren, was bereits im Wörterbuch vorhanden ist (der Konstruktor hat möglicherweise zuerst Elemente hinzugefügt). –

+0

Sortierung, ja ... aber es wird auch verwendet, um die Anfangswerte in der Sammlung festzulegen, also passt es auf diese Weise. –

+0

Richtig. Das fehlende 'new' sollte eine rote Fahne sein ... aber ohne diese Syntax zu benutzen, habe ich den Gleichheitsoperator zu wörtlich genommen. –

0

Es schlägt mit einer NULL-Referenzausnahme fehl, weil Sie eine Variable (Dictionary) deklariert haben, die nicht erkannt wird, daher ist sie null.

Wenn Sie versuchen, die Einträge mithilfe der Initialisierungssyntax hinzuzufügen, versuchen Sie, Daten in ein Nullobjekt zu schreiben.

Wenn Sie die Zeile durch ein "= new Dictionary ..." ersetzen, erstellen Sie ein neues Objekt für Dictionary, auf das verwiesen werden kann, und Sie können dann erfolgreich Einträge hinzufügen.

(In Jon Skeet Beispiel muss der Controls-Auflistung bereits durch das Formular wurden, erstellt daher funktioniert es ok)

+0

Ja, natürlich. Meine Frage war: Warum erlaube ich diese Syntax? –

+0

Fair genug.Jon antwortete auf deine Frage, also dachte ich, ich würde den Grund für den Fall eingeben, dass du den Fehler nicht verstanden hast. –

4

Sie noch die Syntax, die Sie in einem Konstruktor wollen verwenden können:

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