2016-07-14 16 views
3

vorgeschlagen Ich habe ein seltsames Problem mit der Objektinitialisierersyntax.NullReferenceException mit Objektinitialisierer von Resharper

Hier sind meine Beispielklassen:

public class Foo 
{ 
    public Bah BahProp { get; set; } 
} 

public class Bah 
{ 
    public int Id { get; set; } 
} 

Betrachten wir drei Möglichkeiten, folgende ein Objekt zu initialisieren:

Die alte, ausführliche, aber explizite Weise richtig funktioniert:

var foo1 = new Foo(); 
foo1.BahProp = new Bah(); 
foo1.BahProp.Id = 1; 
// correctly initialized 

Die zweite So benutze ich immer object initializer Syntax:

Ein dritte Weg resharper hat meinen Kollegen mit einer anderen resharper Version vorgeschlagen (ist es ein Bug?):

var foo3 = new Foo 
{ 
    BahProp = { Id = 1 } 
}; // NullReferenceException 

Was der letzte Ansatz ist anders zu machen?

Meine Nachschärfer Version ist 2016.1.1, meine Kollegin war am 10.02. Mein Reshaper schlug den zweiten Weg vor. Aber was macht der dritte Weg und wann ist er nützlich?

Update: Es scheint also, dass es eine schlechte Resharper-Sugestion war, den letzten Weg zu benutzen, deshalb haben sie es inzwischen geändert, um den zweiten Weg zu benutzen.

Sie können die NullReferenceException vermeiden, wenn Sie die dritte Möglichkeit verwenden möchten, indem Sie alle Eigenschaften/Felder initialisieren, die Referenztypen inline oder im Konstruktor sind.

Ich werde definitiv nicht diese seltsame Eigenschaft Zuweisung Syntax verwenden.

+0

Ich würde die kompilierte .dll mit ILSpy oder einem anderen Decompiler überprüfen, um zu sehen, was der Compiler anders gemacht hat – Waescher

+0

* "Ich werde definitiv nicht diese seltsame Eigenschaft Zuweisung Syntax" *. – Sinatr

Antwort

6
new Foo { BahProp = { Id = 1 } } 

kompiliert:

new Foo().BahProp.Id = 1; 

oder wenig ausführlicher:

var foo3 = new Foo(); 
foo3.BahProp.Id = 1; 

So BahProp null ist. Du bist nicht Konstruieren es.
(Dies ist vielleicht die verwirrendste Syntax in allen C#)
Option 2 funktioniert, weil Sie den Konstruktor von Bah aufrufen.

Option 3 funktioniert auch, wenn Sie BahProp im Konstruktor von Foo initialisieren. Es wird bis zu dem Zeitpunkt BahProp = { Id = 1 } konstruiert sein.

public class Foo { 
    public List<int> Numbers { get; set; } 
} 

var foo = new Foo { Numbers = { 1, 2, 3 } }; 

initialisieren Dies schließt nicht die Liste:

Das gleiche ist mit Auflistungsinitialisierer gesehen. Es ruft nur Hinzufügen auf.

Sie müssen wirklich new MyObject() { X = 1, Y = 2 } als zwei getrennte Teile sehen:
new MyObject() erstellt ein neues Objekt und
{ X = 1, Y = 2 } setzt die Werte seiner Eigenschaften (und das ist alles, es tut).
Objekt- und Auflistungsinitialisierer können verschachtelt werden. Der Initialisierer der obersten Ebene muss einem Konstruktor folgen, ein verschachtelter Initialisierer jedoch nicht.

+0

Danke. Beachten Sie, dass ich meine Bah-Klasse geändert habe, da der Typ der Eigenschaft keine Rolle spielt. Es muss kein Bezug zueinander sein. Wenn '{Id = 1} 'den Standardkonstruktor von' Bah 'nicht implizit aufruft, wann ist es überhaupt nützlich? Haben Sie einen Link zu MSDN? –

+0

@TimSchmelter Ich denke nicht, dass Sie diesen speziellen Fall auf MSDN finden können. Ich habe es gerade auf http://tryroslyn.azurewebsites.net/ –

+0

ausprobiert, aber diese Initialisierungssyntax muss irgendwo dokumentiert werden: 'BahProp = {Id = 1}'. Oder ist keine Initialisersyntax, sondern nur eine seltsame Eigenschaftszuweisung. Ich fürchte, es ist immer noch nicht klar. –