Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

216
Views
C# complex type initializer compiles without new keyword

I was recently working on some code, that has changed from using decimal to use a complex type that has the decimal number and a type to represent a fraction. I had to update some tests, and while typing I forgot to add the new keyword. The code compiled but the test kept failing, throwing a NullReferenceException. There I realized the missing new and that the property was not initialized. Has anybody an idea why this happening? I could not find anything in the C# lang specification that would explain this.

Here is the code sample:

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 
         }
     }
}

Please note that I'm using C# 6 and VS 2015, but I get the same result also in LINQPad.

If somebody could explain this (I'm looking in your direction Jon Skeet :) ) I would be glad.

about 4 years ago · Santiago Trujillo
3 answers
Answer question

0

The C# Specification 5.0 defines object initializer as (7.6.10.2 Object initializers):

An object initializer specifies values for zero or more fields or properties of an object.

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

And after the detailed explanation there is an example given which is very similar to your code:

If Rectangle’s constructor allocates the two embedded Point instances

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

the following construct can be used to initialize the embedded Point instances instead of assigning new instances:

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

which has the same effect as

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

But there is only one difference, the Point instances here are initialized inside of the Rectangle class which occurs in the constructor of Rectangle.

So the syntax is valid by the specification, but you need to make sure Value is initialized before using the object initializer to initialize its properties in order to avoid NRE.

about 4 years ago · Santiago Trujillo Report

0

An object-initializer doesn not really instantiate your members.

See the following code:

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

This compiles to:

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

In your case you forgot to instantiate MyMember, thus the object-intializer tries to access that property and assign further values to it. This is due to the fact that object-initializers allways run after the appropriate constructor, which wasn´t called in your case. So in your case it compiles to this:

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

Causing a NullReferenceException as myMember was never instantiated.

Why does this even compile? Well, I assume the compiler assumes that you instantiate MyMember within the constructor of MyInstance. It can´t know wheather you actually did this.

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

Leaving members null is of course absoluetely valid.

about 4 years ago · Santiago Trujillo Report

0

The object initializer syntax allows you to initialize an object without creating it first. This is rather important if you want to preserve object identity.

For example, you could make ClassA.Value a read-only property, and initialize it in the object constructor:

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

  public MyDecimal Value { get; private set; }
}

This behaviour is of course explicitly outlined in the C# specification (excerpt from version 5):

7.6.10.2 Object initializers

A member initializer that specifies an expression after the equals sign is processed in the same way as an assignment (§7.17.1) to the field or property.

A member initializer that specifies an object initializer after the equals sign is a nested object initializer, i.e. an initialization of an embedded object. Instead of assigning a new value to the field or property, the assignments in the nested object initializer are treated as assignments to members of the field or property. Nested object initializers cannot be applied to properties with a value type, or to read-only fields with a value type.

Since your Value initializer is a nested initializer, it allows you to just assign members of Value without initializing it - as long as Value has been initialized already, of course. The compiler has no way of verifying whether Value is null, so it cannot give you an error.

about 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!