2010-10-01 16 views
16

Este código se compila correctamente, pero creo que no debería compilarse. Además, cuando lo ejecutas obtienes un NullReferenceException. El código que falta es la "nueva barra" en la inicialización de la propiedad Bar.¿Es esto un error en el compilador 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" } 
         }; 
    } 
} 

¿Es esto un error conocido?

+3

¿Por qué cree que debería dejar de compilar? No asumiría que es un error de compilación del bate. –

+0

Sí, es una función conocida. – leppie

+0

Porque no hay forma de que esto funcione – Maxm007

Respuesta

41

¿Por qué crees que no debería compilarse? Es la sintaxis del inicializador de objetos anidados, y es responsabilidad del código del cliente proporcionar un valor válido para la inicialización.

De la documentación:

C# spec 7.5.10.2 "inicializadores de objeto"

A inicializador miembro que especifica un inicializador objeto después del signo igual es un inicializador objeto anidado, es decir, una inicialización de un objeto incrustado. En lugar de asignar un nuevo valor en el campo o la propiedad, las asignaciones en el inicializador de objeto anidado son tratados como las asignaciones a los miembros del campo o propiedad

+1

¡Guau, no lo sabía! Muchas gracias. –

+0

Gran descripción del problema. – NotMe

+0

Gracias. ¡Buena respuesta! –

3

El new es innecesario en un inicializador de objeto:

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 

Es el último que es más importante. Representa el lado derecho de su sintaxis property = value. Esto significa que el lado derecho puede ser una expresión C# normal (con un operador new) o otro iniciador. En cuyo caso, todo lo que necesita son los aparatos de apertura y cierre.

+0

Sí, entendí que el nuevo no es necesario, pero ¿dónde está el tipo de barra? – Maxm007

+0

Se infiere porque el tipo se conoce en función de la propiedad que se inicializa. –

+0

así que si se deduce que es una barra, y luego asume su Nueva barra, ¿por qué arroja nullrefexception. – Maxm007

1

Bar es una propiedad de Foo, por lo que se le permite acceder a ella y la asignación de una propiedad de nombre en tiempo de compilación, pero en tiempo de ejecución comprueba la instancia válida de Bar que no está presente de manera lanzando excepción de referencia nula, será el caso con cualquier versión de C#.

16

No, esto no es un error.

Si desea que se ejecute, coloque new antes Bar (tal como lo hizo para Foo antes del inicializador) o cree el objeto Bar en el constructor de Foo.

El inicializador de objetos es esencialmente solo azúcar sintáctico.

Este:

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

es exactamente lo mismo que esto:

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

Si cambia su código a la siguiente equivalente, también recibirá un error de ejecución de un NullReferenceException en lugar de una tiempo de compilación error/advertencia.

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

El efecto es el mismo, la barra nunca se inicializa correctamente. Ahora bien, desde la perspectiva de los compiladores de compiladores, es extremadamente difícil determinar en todos los casos si la barra se inicializó correctamente antes de su uso.

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

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

Esto compilará y no lanzar ninguna excepción, así que no es un error, que sólo estás inicializar un objeto inexistente:

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 una muestra de trabajo .

Su fácil, solamente añadir un "nueva barra()" trabajo un bien que


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(); 
    } 
} 
Cuestiones relacionadas