4

I have a strange issue with the object initializer syntax.

Here are my sample classes:

public class Foo
{
    public Bah BahProp { get; set; }
}

public class Bah
{
    public int Id { get; set; }
}

Consider following three ways to initialize an object:

The old, verbose but explicit way, working correctly:

var foo1 = new Foo();
foo1.BahProp = new Bah();
foo1.BahProp.Id = 1;
// correctly initialized

The second way i'm always using, using object initializer syntax:

var foo2 = new Foo
{
    BahProp = new Bah { Id = 1 }
}; // correctly initialized

A third way resharper has suggested my collegue with a different resharper version(is it a bug?):

var foo3 = new Foo
{
    BahProp = { Id = 1 }
};  // NullReferenceException

What is the last approach doing differently?

My resharper version is 2016.1.1, my colleague was on 10.02. My resharper suggested the second way. But what does the third way do and when is it useful?

Update: So it seems that it was a bad resharper sugestion to use the last way, that's why they have changed it meanwhile to use the second way.

You can avoid the NullReferenceException if you want to use the third way by initializing all properties/fields that are reference types inline or in the constructor.

I will definitely not use this strange property assignment syntax.

2
  • I would check the compiled .dll with ILSpy or any other decompiler to see what the compiler did differently Commented Jul 14, 2016 at 9:10
  • "I will definitely not use this strange property assignment syntax". Commented Jan 12, 2018 at 15:42

1 Answer 1

7
new Foo { BahProp = { Id = 1 } }

compiles to:

new Foo().BahProp.Id = 1;

or, little more verbose:

var foo3 = new Foo();
foo3.BahProp.Id = 1;

So BahProp is null. You're not constructing it.
(This is perhaps the most confusing syntax in all of C#)
Option 2 works because you're calling the constructor of Bah.

Option 3 would also work if you initialize BahProp inside the constructor of Foo. It will have been constructed by the time BahProp = { Id = 1 } is called.

The same is seen with collection initializers:

public class Foo {
    public List<int> Numbers { get; set; }
}

var foo = new Foo { Numbers = { 1, 2, 3 } };

This does not initialize the List. It only calls Add on it.

You really must see new MyObject() { X = 1, Y = 2 } as two distinct parts:
new MyObject() constructs a new object and
{ X = 1, Y = 2 } sets the values of its properties (and that's all it does).
Object and collection initializers can be nested. The top-level initializer must follow a constructor, but a nested initializer does not.

Sign up to request clarification or add additional context in comments.

12 Comments

Thanks. Note that i've modified my bah class since the type of the property doesn't matter. It doesn't need to be a reference to each other. If { Id = 1 } does not call the default constructor of Bah implicitely, when is it useful at all? Do you have a link to MSDN?
@TimSchmelter I don't think you can find this particular case on MSDN. I just tried it out on tryroslyn.azurewebsites.net
but this initializer syntax must be documented somewhere: BahProp = { Id = 1 }. Or is is not an initializer syntax but only a strange property assignment. I'm afraid it's still not clear.
All { SomeProperty = someValue } does is set the value of SomeProperty. It just allows you to do it all in one statement. It does not call any constructor implicitly.
So the correct way was to initialize all fields/properties which are reference types in the constructor.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.