2010-10-01 14 views
16

Questo codice viene compilato correttamente, ma penso che non dovrebbe riuscire a compilare. Inoltre, quando lo esegui ottieni un NullReferenceException. Il codice mancante è la "nuova barra" nell'inizializzazione della proprietà Bar.Si tratta di un bug nel compilatore C# 4.0?

class Bar 
{ 
    public string Name { get; set; } 
} 

class Foo 
{ 
    public Bar Bar { get; set; } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var foo = new Foo 
         { 
          Bar = { Name = "Hello" } 
         }; 
    } 
} 

È un bug noto?

+3

Perché pensi che dovrebbe riuscire a compilare? Non darei per scontato che si tratti di un bug del compilatore. –

+0

Sì, è una funzione nota. – leppie

+0

Perché non c'è modo che questo possa mai funzionare – Maxm007

risposta

41

Perché pensi che non dovrebbe riuscire a compilare? È la sintassi di inizializzatore di oggetti nidificati ed è responsabilità del codice client fornire un valore valido per l'inizializzazione.

Dalla documentazione:

C# spec 7.5.10.2 "inizializzatori oggetto"

Un inizializzatore membro che specifica un inizializzatore oggetto dopo il segno di uguale è un inizializzatore di oggetto nidificato, vale a dire un'inizializzazione di un oggetto incorporato. Invece di assegnare un nuovo valore al campo o proprietà, le assegnazioni del inizializzatore oggetto nidificata vengono trattati come assegnazioni ai membri del campo o della proprietà

+1

Wow, non lo sapevo! Molte grazie. –

+0

Ottima descrizione del problema. – NotMe

+0

Grazie. Buona risposta! –

3

Il new è unecessary in un inizializzatore oggetto:

object-creation-expression: 
    new type ( argument-list(opt) ) object-or-collection-initializer(opt) 
    new type object-or-collection-initializer 

object-or-collection-initializer: 
    object-initializer 
    collection-initializer 

object-initializer: 
    { member-initializer-list(opt) } 
    { member-initializer-list , } 

initializer-value: 
    expression 
    object-or-collection-initializer 

È l'ultimo che è più importante. Rappresenta il lato destro della sintassi property = value. Ciò significa che il lato destro può essere una normale espressione C# (con un operatore new) o un altro initalizzatore. In tal caso, tutto ciò che serve sono le parentesi graffe di apertura e chiusura.

+0

Sì, ho capito che il nuovo non è necessario ma dov'è il tipo di barra? – Maxm007

+0

Derivato perché il tipo è noto in base alla proprietà inizializzata. –

+0

quindi se ne ha dedotto una barra, e quindi assume la sua nuova barra, perché lancia la nullrefecisione. – Maxm007

1

Bar è una struttura di Foo, quindi è che consente di accedere e l'assegnazione di una proprietà nome in fase di compilazione, ma in fase di esecuzione controlla per l'istanza valida di Bar che non è presente in modo lanciando un'eccezione di riferimento null, sarà il caso con qualsiasi versione C#.

16

No questo non è un bug.

Se vuoi farlo, metti uno new prima dello Bar (proprio come hai fatto per Foo prima dell'inizializzatore) o crei l'oggetto Bar nel costruttore di Foo.

L'inizializzatore dell'oggetto è essenzialmente solo zucchero sintattico.

questo:

var foo = new Foo 
      { 
       Bar = { Name = "Hello" } 
      }; 

è esattamente lo stesso di questo:

var foo = new Foo(); 
foo.Bar.Name = "Hello"; 
2

Se si modifica il codice per il seguente equivalente, si riceverà anche un errore di runtime di un NullReferenceException invece di un errore/avviso di compilazione del tempo.

static void Main(string[] args) { 
    Foo foo2 = new Foo(); 
    foo2.Bar.Name = "test"; 
} 

L'effetto è lo stesso, la barra non è mai inizializzata correttamente. Ora, dal punto di vista degli scrittori di compilatori, è estremamente difficile determinare in tutti i casi se la barra sia stata inizializzata correttamente prima dell'uso.

2
... 
Bar = { Name = "Hello"} 
... 

significa: Foo.Bar.Name="Hello" non : {Foo.Bar=new Bar(); Foo.Bar.Name="Hello";}

Questo compilerà e non lanciare alcuna eccezione, quindi non è un bug, sei solo l'inizializzazione di un oggetto inesistente:

class Bar 
{ 
    public string Name; 
} 
class Foo 
{ 
private Bar _bar = new Bar(); 
public Bar Bar 
{ 
    get { return _bar; } 
    set { _bar = value; } 
} 
} 
class Program 
{ 
static void Main(string[] args) 
{ 
    Foo foo = new Foo 
    { 
    Bar = { Name = "Hello"} 
    }; 
} 
} 
0

Creo un campione operativo .

La sua facile, solo aggiungere un "nuova Bar()" un lavoro fine che


class Bar 
{ 
    public string Name { get; set; } 
} 

class Foo 
{ 
    public Bar Bar { get; set; } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var foo = new Foo 
         { 
          Bar = new Bar() { Name = "Hello" } 
         }; 

     Console.WriteLine(foo.Bar.Name); 
     Console.ReadLine(); 
    } 
}