new lista initialize inicializar c# compiler-construction object-initializers

lista - new list object c#



¿Es este un error en el compilador de C#4.0? (7)

Este código se compila correctamente, pero creo que debería fallar en compilar. Además, cuando lo ejecutas obtienes una NullReferenceException . El código que falta es la "nueva barra" en la inicialización de la propiedad Bar .

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?


¿Por qué crees que debería dejar de compilar? 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 objetos"

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


Creo una muestra de trabajo .

Es fácil, solo agregue un "nuevo Bar ()" y funcionará bien

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


Lo new es necesario en un inicializador de objetos:

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 el más importante. Representa el lado derecho de la sintaxis de su property = value . Esto significa que el lado derecho puede ser una expresión normal de c # (con un new operador) u otro inicializador. En cuyo caso, todo lo que necesitas son las llaves de apertura y cierre.


No esto no es un error.

Si desea que se ejecute, puede poner una new Bar antes (como lo hizo para Foo antes del inicializador) o crear el objeto Barra en el constructor de Foo.

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

Esta:

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

Es exactamente lo mismo que esto:

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


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

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, desde la perspectiva de los compiladores, es extremadamente difícil determinar en todos los casos si Bar se inicializó correctamente antes de usarlo.


Bar es una propiedad de Foo , por lo que le permite acceder y asignar una propiedad de nombre en el momento de la compilación, pero en el tiempo de ejecución verifica la instancia válida de Bar que no está presente, por lo que al lanzar una excepción de referencia nula será la caso con cualquier versión de C #.


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

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

Esto compilará y no lanzará ninguna excepción, así que no es un error, solo está inicializando 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"} }; } }