Is There Any Benefit of Using an Object Initializer

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.

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.

Are there any downsides to using an empty object initializer?

The compiled result is the same.

The following C#:

static void Main()
{
var x = new List<int>();
var y = new List<int> { };
}

Compiles into the following IL:

.method private hidebysig static 
void Main () cil managed
{
// Method begins at RVA 0x2050
// Code size 14 (0xe)
.maxstack 1
.entrypoint
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<int32> x,
[1] class [mscorlib]System.Collections.Generic.List`1<int32> y
)

IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.0
IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_000c: stloc.1
IL_000d: ret
} // end of method Program::Main

If you add a value to the collections:

static void Main()
{
var x = new List<int>();
x.Add(1);
var y = new List<int> { 1 };
}

This is the resulting IL:

.method private hidebysig static 
void Main () cil managed
{
// Method begins at RVA 0x2050
// Code size 32 (0x20)
.maxstack 2
.entrypoint
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<int32> x,
[1] class [mscorlib]System.Collections.Generic.List`1<int32> y,
[2] class [mscorlib]System.Collections.Generic.List`1<int32> '<>g__initLocal0'
)

IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldc.i4.1
IL_0009: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_000e: nop
IL_000f: newobj instance void class [mscorlib]System.Collections.Generic.List`1<int32>::.ctor()
IL_0014: stloc.2
IL_0015: ldloc.2
IL_0016: ldc.i4.1
IL_0017: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<int32>::Add(!0)
IL_001c: nop
IL_001d: ldloc.2
IL_001e: stloc.1
IL_001f: ret
} // end of method Program::Main

This shows how collection initializers are only syntax sugar. Because collection initializers were not originally part of C#, I think people are more used to the constructor syntax. If I came across some code that used an empty collection initializer, I would wonder to myself why, but it certainly doesn't have any severe readability issues. If one is intelligent enough to understand code at all, then {} vs () shouldn't be so upsetting that it undermines one's ability to comprehend what the code is doing. It comes down to a matter of opinion. Do what your team agrees on, and if it's just you, then use it to your hearts content.

What are the advantages of C# object/list initializer syntax?

There is no run time difference between these two pieces of code. They will both compile down to the same IL.

The primary advantage of the initializer syntax would be that it basically initializes a list in a single expression as opposed to across multiple statements. For example, you could use it to return a list from a method without explicitly creating a temporary variable (the compiler creates this temporary for you):

public List<T> MakeListOf3<T>( T val )
{
return new List<T> { val, val, val };
}

As opposed to:

public List<T> MakeListOf3<T>( T val )
{
var list = new List<T>();
list.Add( val );
list.Add( val );
list.Add( val );
return list;
}

That's quite contrived, but you get the idea.

Setting properties via object initialization or not : Any difference ?

They are almost exactly equivalent except that the first method (using an object initializer) only works in C# 3.0 and newer. Any performance difference is only minor and not worth worrying about.

They produce almost identical IL code. The first gives this:

.method private hidebysig instance void ObjectInitializer() cil managed
{
.maxstack 2
.locals init (
[0] class Person person,
[1] class Person <>g__initLocal0)
L_0000: newobj instance void Person::.ctor()
L_0005: stloc.1
L_0006: ldloc.1
L_0007: ldstr "Philippe"
L_000c: callvirt instance void Person::set_Name(string)
L_0011: ldloc.1
L_0012: ldstr "phil@phil.com"
L_0017: callvirt instance void Person::set_Mail(string)
L_001c: ldloc.1
L_001d: stloc.0
L_001e: ldloc.0
L_001f: callvirt instance string [mscorlib]System.Object::ToString()
L_0024: pop
L_0025: ret
}

The second gives this:

.method private hidebysig instance void SetProperties() cil managed
{
.maxstack 2
.locals init (
[0] class Person person)
L_0000: newobj instance void Person::.ctor()
L_0005: stloc.0
L_0006: ldloc.0
L_0007: ldstr "Philippe"
L_000c: callvirt instance void Person::set_Name(string)
L_0011: ldloc.0
L_0012: ldstr "phil@phil.com"
L_0017: callvirt instance void Person::set_Mail(string)
L_001c: ldloc.0
L_001d: callvirt instance string [mscorlib]System.Object::ToString()
L_0022: pop
L_0023: ret
}

As you can see, nearly identical code is generated. See below for the exact C# code I compiled.

Performance measurements show very similar results with a very small performance improvement for using the object initializer syntax:


Method Iterations per second
ObjectInitializer 8.8 million
SetProperties 8.6 million

Code I used for testing the performance:

using System;

class Person
{
public string Name { get; set; }
public string Mail { get; set; }
}

class Program
{
private void ObjectInitializer()
{
Person person = new Person()
{
Name = "Philippe",
Mail = "phil@phil.com",
};
person.ToString();
}

private void SetProperties()
{
Person person = new Person();
person.Name = "Philippe";
person.Mail = "phil@phil.com";
person.ToString();
}

private const int repetitions = 100000000;

private void Time(Action action)
{
DateTime start = DateTime.UtcNow;
for (int i = 0; i < repetitions; ++i)
{
action();
}
DateTime end = DateTime.UtcNow;
Console.WriteLine(repetitions / (end - start).TotalSeconds);
}

private void Run()
{
Time(ObjectInitializer);
Time(SetProperties);
Console.WriteLine("Finished");
Console.ReadLine();
}

private static void Main()
{
new Program().Run();
}
}

Use object initializer - Resharper suggestion

The second contains less characters and so is more compact to read. You don't have to repeat myClass 2 more times, and the initialization logic is in one block.

It is really a syntactic sugar that doesn't change a thing in the generated code. If you doesn't like it, you can always disable the warning on ReSharper.

A longer post on the advantages of using Object Initializers here:

  • Setting properties via object initialization or not : Any difference ?
  • Is there any benefit of using an Object Initializer?

Is there a performance improvement if using an object initializer, or is it asthetic?

It's actually potentially very, very slightly slower to use an object initializer than to call a constructor and then assign the properties, as it has one extra assignment:

MyClass foo = new MyClass();
foo.Property1 = 4;
foo.Property2 = "garfield";

vs

MyClass tmp = new MyClass();
tmp.Property1 = 4;
tmp.Property2 = "garfield";
MyClass foo = tmp;

The properties are all assigned before the reference is assigned to the variable. This difference is a visible one if it's reusing a variable:

using System;

public class Test
{
static Test shared;

string First { get; set; }

string Second
{
set
{
Console.WriteLine("Setting second. shared.First={0}",
shared == null ? "n/a" : shared.First);
}
}

static void Main()
{
shared = new Test { First = "First 1", Second = "Second 1" };
shared = new Test { First = "First 2", Second = "Second 2" };
}
}

The output shows that in the second line of Main, when Second is being set (after First), the value of shared.First is still "First 1" - i.e. shared hasn't been assigned the new value yet.

As Marc says though, you'll almost certainly never actually spot a difference.

Anonymous types are guaranteed to use a constructor - the form is given in section 7.5.10.6 of the C# 3 language specification.

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.



Related Topics



Leave a reply



Submit