C# 3.0 New Feature for the Week #2: Object and Collection Initializers

November 16, 2007

tags: ,
no comments

Last week I started my series of posts about new C# 3.0 features, and my second post will be about object and collection initializers. I will also include a bonus – an easy way of having a collection initializer in C# 2.0.

Object Initializers

Say we have declared the following class (with the automatic properties syntax we learned about last week):

public class Person { public string FirstName {get; set;} public string LastName {get; set; } }

We can now initiate a Person in the following way:

Person p = new Person { FirstName = "Doron", LastName = "Yaacoby"};

Note that Person only has the default constructor, that accepts no parameters, and yet we have one line initialization for it. In C# 2.0 we have this ability as well, but only for attributes.

[System.AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] public sealed class CachedAttribute : OnMethodInvocationAspect

In the first example Person has to have a default constructor, since as we’ll see, the compiler will convert our code to use it, and then set the properties. Of course that in that case, we could use one of the other constructors. It would look something like this.

Person p = new Person("Doron") {LastName = "Yaacoby" };

One might ask, why can’t we always use a constructor? Well, a constructor doesn’t usually include all properties – this allows for much more flexibility for object initialization. Also, it is a lot more readable than using a constructor, since the reader of the code can immediately see which properties we’re initializing, instead of having to look at the constructor signature to understand. 

How is it implemented?

Lets have a look at the Reflector.

1 Person <>g__initLocal0 = new Person(); 2 <>g__initLocal0.FirstName = "Doron"; 3 <>g__initLocal0.LastName = "Yaacoby"; 4 Person p = <>g__initLocal0;

Again, rather obvious. The only question that comes to mind is, why bother creating a local variable and then setting our own variable to it? Why not just use “p” from the first moment? I’m guessing that the first 3 lines is the compiler’s direct translation to “new Person{FirstName=…,LastName=…}”. Say we’re calling a method like this:

ToXml(new Person {FirstName = "Doron", LastName = "Yaacoby"});

Then in this case, the compiler would have to create a local variable in order to pass it to the method. When we were initializing “p”, that variable was not required, but I guess the compiler doesn’t bother to take a shortcut in this case.

Edit: Shani pointed me to a better explanation for this issue: having an atomic assignment. Thanks!

Collection Initializers

In a similar manner, we now have a shortcut for initializing collections.

List<string> names = new List<string> { "Team", "Fortress", "2"};

Rather like the way we could always initialize arrays, but now it works for any collection. Actually, it will work for any class that implements IEnumerable and has an appropriate Add method. We could also combine object initialization here:

Dictionary<int,Person> peopleDictionary = new Dictionary<int,Person> { {1, new Person { FirstName = "Doron"} } }

Here we initialized a dictionary of type int->Person. This dictionary implements IEnumerable and it has the method Add(int key, Person value). And so we initialize the dictionary with one key-value pair, that maps the integer 1 to the Person Doron.

How is it implemented?

Once again, let us reflect on our first example.

List<string> <>g__initLocal1 = new List<string>(); <>g__initLocal1.Add("Team"); <>g__initLocal1.Add("Fortress"); <>g__initLocal1.Add("2");

No surprises here. The compiler changes our code to creation of a list, and repeating calls to “Add”. Although one thing to notice is that there’s no use of the IEnumerable interface. So why is it required for usage of this syntax? For your code to make sense would be the logical answer. Consider the following code:

public class Calculator { public double Add (double x, double y) { return x + y; } } public void TestCalc() { Calculator c = new Calculator { 4, 2 }; }

Now if we didn’t have the IEnumerable restriction this would actually compile, but would be absolutely meaningless.

Bonus: Collection Initializer with C# 2.0

We could simulate the behavior of a collection initializer by creating the following class.

public class ExtendedList<T>: List<T> { public ExtendedList(params T[] initalValues) { AddRange(initalValues); } }

Which can later be used this way:

ExtendedList<string> names = new ExtendedList<string>("Team", "Fortress" , "2");

Of course this is not as great as something that works with every IEnumerable, but I have found this to be quite useful, especially in unit-testing where you usually create test collections with a few parameters. You can download the complete class here.

Hope you enjoyed this. See you next week, with another new C# 3.0 feature.

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>