What's the Difference Between an Object Initializer and a Constructor

What's the difference between an object initializer and a constructor?

Object Initializers were something added to C# 3, in order to simplify construction of objects when you're using an object.

Constructors run, given 0 or more parameters, and are used to create and initialize an object before the calling method gets the handle to the created object. For example:

MyObject myObjectInstance = new MyObject(param1, param2);

In this case, the constructor of MyObject will be run with the values param1 and param2. These are both used to create the new MyObject in memory. The created object (which is setup using those parameters) gets returned, and set to myObjectInstance.

In general, it's considered good practice to have a constructor require the parameters needed in order to completely setup an object, so that it's impossible to create an object in an invalid state.

However, there are often "extra" properties that could be set, but are not required. This could be handled through overloaded constructors, but leads to having lots of constructors that aren't necessarily useful in the majority of circumstances.

This leads to object initializers - An Object Initializer lets you set properties or fields on your object after it's been constructed, but before you can use it by anything else. For example:

MyObject myObjectInstance = new MyObject(param1, param2)
{
MyProperty = someUsefulValue
};

This will behave about the same as if you do this:

MyObject myObjectInstance = new MyObject(param1, param2);
myObjectInstance.MyProperty = someUsefulValue;

However, in multi-threaded environments the atomicity of the object initializer may be beneficial, since it prevents the object from being in a not-fully initialized state (see this answer for more details) - it's either null or initialized like you intended.

Also, object initializers are simpler to read (especially when you set multiple values), so they give you the same benefit as many overloads on the constructor, without the need to have many overloads complicating the API for that class.

Should I use an object initializer or a constructor?

I currently see the following problems with using them:

  1. The properties that are assigned have to be changeable. This seems
    undesirable because if the data is passed to a constructor I can
    check it there and make object creation fail if the data provided is
    insufficient or wrong. If data can be assigned with a property I
    suddenly have to figure out what the state of my object is, whether
    everything is properly created yet or which other state I might be
    in.
  2. The properties that are assigned have to be public. This means that access to things that might otherwise be private will have to be exposed and then later restricted by using an interface or something like that.

So my working theory is: Don't use object initializers they encourage stupid things.

Constructor vs Object Initializer Precedence in C#

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 on initializing object inside class declaration v/s constructor

The difference here is really subtle, and can only easily be appreciated in IL:

class MyBuilder1
{
private MySynchronizer m_synchronizer = new MySynchronizer();

public MyBuilder1()
{

}
}

gives us the constructor:

.method public hidebysig specialname rtspecialname 
instance void .ctor () cil managed
{
// Method begins at RVA 0x2050
// Code size 18 (0x12)
.maxstack 8

IL_0000: ldarg.0
IL_0001: newobj instance void MySynchronizer::.ctor()
IL_0006: stfld class MySynchronizer MyBuilder1::m_synchronizer
IL_000b: ldarg.0
IL_000c: call instance void [mscorlib]System.Object::.ctor()
IL_0011: ret
} // end of method MyBuilder1::.ctor

where-as this:

class MyBuilder2
{
private MySynchronizer m_synchronizer;

public MyBuilder2()
{
m_synchronizer = new MySynchronizer();

}
}

gives us:

// Methods
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2063
// Code size 18 (0x12)
.maxstack 8

IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ldarg.0
IL_0007: newobj instance void MySynchronizer::.ctor()
IL_000c: stfld class MySynchronizer MyBuilder2::m_synchronizer
IL_0011: ret
} // end of method MyBuilder2::.ctor

The difference is simply one of ordering:

  • field initializers (MyBuilder1) happen before the base-type constructor call (object is the base here; call instance void [mscorlib]System.Object::.ctor() is the base-constructor call)
  • constructors happen after the base-type constructor call

In most cases, this won't matter. Unless your base-constructor invokes a virtual method that the derived type overrides: then whether or not the field has a value in the overridden method will be different between the two.

What's the difference between an instance initializer and a constructor?

The code inside the braces with no names will be part of the constructor of the class and be executed before the logic contained in the class constructor.

Quick example:

public class Foo {
{
System.out.println("Before Foo()");
}

public Foo() {
System.out.println("Inside Foo()");
}

{
System.out.println("Not After Foo()");
}
}

difference between initializing an object with these two ways in c#


so does anyone have any idea about the difference between these various ways to initializing an object ?

There's no difference at all. In both cases you're using an object initializer, and if you don't specify any constructor arguments, that's exactly equivalent to providing an empty list of constructor arguments. From section 7.6.10.1 of the C# spec:

An object creation expression can omit the constructor argument list and enclosing parentheses provided it includes an object initializer or collection initializer. Omitting the constructor argument list and enclosing parentheses is equivalent to specifying an empty argument list.

Note that when you just invoke a constructor without using an object initializer (the braces) you have to specify the constructor arguments. So:

Foo foo = new Foo();    // Valid
Foo foo = new Foo; // Invalid
Foo foo = new Foo() {}; // Valid
Foo foo = new Foo {}; // Valid

The "valid" lines are all exactly equivalent, including any use of default parameters - so Foo might only have a constructor like this:

// You can invoke this without specifying arguments
public Foo(int x = 0)
{
}

See section 7.6.10 of the C# 5 spec for more details.

Object Initializer vs Constructor in C# when many arguments are required

One of my favorite things to do when creating an object from a data source (SQL, files, XML, etc) is make a constructor that takes the data source itself.

In your case, you can make a constructor or static factory method that takes an XmlNode (or however you're representing a transaction) and takes care of reading values from the source itself.

Example of both methods:

public class WalletTransaction
{
public string TransactionDateTime { get; private set; }
public int TransactionID { get; private set; }
public int Quantity { get; private set; }
// More omitted for length

// FACTORY METHOD (RECOMMENDED)
public static WalletTransaction Create(XmlNode node)
{
return new WalletTransaction()
{
TransactionDateTime = node.Attributes["transactionDateTime"].Value,
TransactionID = int.Parse(node.Attributes["transactionID"].Value),
Quantity = int.Parse(node.Attributes["quantity"].Value)
};
}

// CTOR METHOD
public WalletTransaction(XmlNode node)
{
TransactionDateTime = node.Attributes["transactionDateTime"].Value;
TransactionID = int.Parse(node.Attributes["transactionID"].Value);
Quantity = int.Parse(node.Attributes["quantity"].Value);
}
}

A static factory would be my preference here, for one big reason. If an exception is thrown in a constructor (say, an int.Parse fails) the actual exception is wrapped in a Type Initialization Exception. A static factory method does not suffer from this drawback and makes debugging a little easier.

You could also ditch the field initializer list in the static method and instead do

var wt = new WalletTransaction();
wt.TransactionDateTime = node.Attributes["transactionDateTime"].Value;
//etc
return wt;

The advantage of this is the ability to do more complex processing. Ie, maybe a field is optional, or only present when another field is set to true.

It seems object initializer is not the same as constructor + property assignment. How so?

Name in NameWithSufix = Name points to data.Name, from which data is null at the time. A better representation for what object initializers do is this:

Data d = new Data();
d.Name = "My Name";
d.NameWithSufix = this.data.Name /*Name*/ + " Sufix"; // <-- see the problem here

this.data = d;

See that this.data isn't set until the object initializer is done.

This is supported by the C# language specification, as noted by PetSerAl.

Should I use an object initializer or a constructor?

I currently see the following problems with using them:

  1. The properties that are assigned have to be changeable. This seems
    undesirable because if the data is passed to a constructor I can
    check it there and make object creation fail if the data provided is
    insufficient or wrong. If data can be assigned with a property I
    suddenly have to figure out what the state of my object is, whether
    everything is properly created yet or which other state I might be
    in.
  2. The properties that are assigned have to be public. This means that access to things that might otherwise be private will have to be exposed and then later restricted by using an interface or something like that.

So my working theory is: Don't use object initializers they encourage stupid things.



Related Topics



Leave a reply



Submit