Constructor vs Object Initializer Precedence in C#
Asked Answered
T

5

67

I've been learning the object initializer in C# recently, but now I'm wondering how it works when it conflicts with the constructor.

public class A
{
    public bool foo { get; set; }

    public A()
    {
        foo = true;
    }

    public A(bool bar)
    {
        foo = bar;
    }
}

What happens when I try this?

public class B
{
    private A a = new A() { foo = false };

    private A b = new A(true) { foo = false };
}

Is a default in the constructor a good way to have a bool that starts true and can be changed?

public A(bool bar = true)
{
    foo = bar;
}
Trackman answered 26/6, 2013 at 18:0 Comment(2)
yes it is still valid with the default initializer, but if you want more than one parameter, the parameter(s) you can forget is only the tail parameter(s).Palimpsest
Right, I've tried it with more complex code in my actual project. Sorry, I guess the "what happens when I do this" part makes it seem like I'm asking just that. I did want a little background/advice about it, though. Couldn't find any docs on it.Trackman
D
56

From the documentation:

The compiler processes object initializers by first accessing the default instance constructor and then processing the member initializations.

This means that in the simplest case (named object initialization) it is basically shorthand (or syntactic sugar) for calling the default constructor and then calling the property setter(s). In the case of anonymous types this kind of initialization is actually required and not mere sugar.

For the 2nd part of your question: It's more of a matter of style but if you have a crucial property I would not create a constructor with a default value. Make the client code set the value explicitly. I'm also not sure why doing something like this: b = A(true) {foo = false}; would be a good idea unless you're in a code obfuscation contest.

Bit of caution though:

... if the default constructor is declared as private in the class, object initializers that require public access will fail.

Difference answered 26/6, 2013 at 18:4 Comment(0)
P
43

Object initializers are just syntactic sugar, in your compiled assembly IL they translate into separate statements, check it on ILSpy.

enter image description here

Phila answered 26/6, 2013 at 18:15 Comment(0)
G
23

The constructor occurs first then the object initializer. Just remember that

a = new A() { foo = false };

is same as

var temp = new A();
temp.foo = false;
a = temp;
Gangling answered 26/6, 2013 at 18:4 Comment(2)
They are not the same. a = new A(); a.foo = false; leaves the object half initialized if an exception was thrown while giving values to its properties. And using the object members will give unexpected result (they will use the default values of there underlying types, e.g. false for boolean members) instead of throwing NullReferenceException. In the other hand, using Object Initializer or Object constructors will make sure that if an exception occur, the object will not be initialized and will give NullReferenceException if we try to use its member (since it's never been initialized).Yerxa
@WaelAlshabani Yes, there is a temporary object that is created and then the property is set to it before it's reference is assigned to the variable. And yes, that is a subtle but important difference if your property might throw an exception and you plan to catch it and still use the reference assigned to the variable for some reason. But none of that applies to this exact example. But I'll update to make this more clear.Gangling
H
15
b = new A(true) {foo = false};

is effectively short for:

A temp = new A(true);
temp.foo = false;
A b = temp;

where temp is an otherwise inaccessible variable. The constructor is always executed first, followed by any initialised properties.

Hamsun answered 26/6, 2013 at 18:4 Comment(0)
M
5

Essentially what Paul has already linked:

From the C# 5 language specification (7.6.10.1)

Processing of an object creation expression that includes an object initializer or collection initializer consists of first processing the instance constructor and then processing the member or element initializations specified by the object initializer or collection initializer.

Mabel answered 26/6, 2013 at 18:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.