Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

222
Vistas
El inicializador de tipo complejo de C# se compila sin una nueva palabra clave

Recientemente estuve trabajando en un código que cambió de usar decimales a usar un tipo complejo que tiene el número decimal y un tipo para representar una fracción. Tuve que actualizar algunas pruebas y, mientras escribía, olvidé agregar la nueva palabra clave. El código se compiló, pero la prueba seguía fallando y arrojaba una NullReferenceException. Ahí me di cuenta de que faltaba nueva y que la propiedad no estaba inicializada. ¿Alguien tiene una idea de por qué sucede esto? No pude encontrar nada en la especificación lang de C# que explicara esto.

Aquí está el ejemplo de código:

 public class Fraction { public int Numerator { get; set; } public int Denominator { get; set; } } public class MyDecimal { public decimal? Decimal { get; set; } public Fraction Fractional { get; set; } } public class ClassA { public MyDecimal Value { get; set; } } //... var instance = new ClassA { Value = // new MyDecimal is missing here { Decimal = 2.0m, Fractional = new Fraction { Numerator = 3, Denominator = 4 } } }

Tenga en cuenta que estoy usando C# 6 y VS 2015, pero también obtengo el mismo resultado en LINQPad.

Si alguien pudiera explicar esto (estoy mirando en tu dirección, Jon Skeet :)), me alegraría.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

La Especificación 5.0 de C# define el inicializador de objetos como ( 7.6.10.2 Inicializadores de objetos ):

Un inicializador de objetos especifica valores para cero o más campos o propiedades de un objeto.

 object-initializer: { member-initializer-listopt } { member-initializer-list , }

Y después de la explicación detallada, se da un ejemplo que es muy similar a su código:

Si el constructor de Rectangle asigna las dos instancias de Point incrustadas

 public class Rectangle { Point p1 = new Point(); Point p2 = new Point(); public Point P1 { get { return p1; } } public Point P2 { get { return p2; } } }

la siguiente construcción se puede usar para inicializar las instancias de Point incrustadas en lugar de asignar nuevas instancias:

 Rectangle r = new Rectangle { P1 = { X = 0, Y = 1 }, P2 = { X = 2, Y = 3 } };

que tiene el mismo efecto que

 Rectangle __r = new Rectangle(); __r.P1.X = 0; __r.P1.Y = 1; __r.P2.X = 2; __r.P2.Y = 3; Rectangle r = __r;

Pero solo hay una diferencia, las instancias de Point aquí se inicializan dentro de la clase Rectangle que se produce en el constructor de Rectangle .

Por lo tanto, la sintaxis es válida según la especificación, pero debe asegurarse de que Value se inicialice antes de usar el inicializador de objetos para inicializar sus propiedades a fin de evitar NRE.

over 4 years ago · Santiago Trujillo Denunciar

0

Un inicializador de objeto realmente no crea una instancia de sus miembros.

Ver el siguiente código:

 var myInstance = new MyInstance { MyMember = new MyMember { Value = 3 }; }

Esto compila a:

 var myMember= new MyMember(); myMember.Value = 3; var myInstance = new MyInstance(); myInstance.MyMember = myMember;

En su caso, olvidó crear una instancia de MyMember , por lo que el inicializador de objetos intenta acceder a esa propiedad y asignarle más valores. Esto se debe al hecho de que los inicializadores de objetos siempre se ejecutan después del constructor apropiado, que no se llamó en su caso. Así que en tu caso se compila a esto:

 var myInstance = new MyInstance(); myMymber.Value = 3;

Causando una NullReferenceException como myMember nunca fue instanciado.

¿Por qué esto incluso compila? Bueno, asumo que el compilador asume que crea una instancia de MyMember dentro del constructor de MyInstance . No puede saber si realmente hiciste esto.

 class Instance { MyMember MyMember = new MyMember(); }

Dejar a los miembros null es, por supuesto, absolutamente válido.

over 4 years ago · Santiago Trujillo Denunciar

0

La sintaxis del inicializador de objetos le permite inicializar un objeto sin crearlo primero. Esto es bastante importante si desea preservar la identidad del objeto.

Por ejemplo, podría convertir ClassA.Value en una propiedad de solo lectura e inicializarla en el constructor de objetos:

 public class ClassA { public ClassA() { Value = new MyDecimal(); } public MyDecimal Value { get; private set; } }

Por supuesto, este comportamiento se describe explícitamente en la especificación de C# (extracto de la versión 5):

7.6.10.2 Inicializadores de objetos

Un inicializador de miembro que especifica una expresión después del signo igual se procesa de la misma manera que una asignación (§7.17.1) al campo o propiedad.

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 la propiedad, las asignaciones en el inicializador de objetos anidados se tratan como asignaciones a miembros del campo o la propiedad. Los inicializadores de objetos anidados no se pueden aplicar a propiedades con un tipo de valor o a campos de solo lectura con un tipo de valor.

Dado que su inicializador de Value es un inicializador anidado, le permite simplemente asignar miembros de Value sin inicializarlo, siempre que Value ya se haya inicializado, por supuesto. El compilador no tiene forma de verificar si Value es null , por lo que no puede darte un error.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda