C# 3.0: I love object and collection initializers


This is the my fourth post in the series of posts I am making on C#3.0. See the previous posts here, here and here


Object and collection initializers are new features in C#3.0 which is syntactic sugar over how you allocate and initialize objects and collections.


Object Initializers


Lets consider a class

class Customer

{

public string name;

public string address;

int age;

public int Age { get { return age; } set { age = value; } }

}


if I wanted to create a object of the type customer and fill up the public variables and properties then in C#2.0 I need to do something like

Customer customer = new Customer();

customer.name = “Abhinaba Basu”;

customer.address = “1835 73rd Ave NE, Medina, WA 98039”;

customer.Age = 99;


With the new object initializer syntax it possible to do all of the above in one statement as in

var cust = new Customer{name = “Abhinaba Basu”, 
address =
“1835 73rd Ave NE, Medina, WA 98039”,
Age = 99 };

This not only reduces lines of code but increases flexibility a lot. So no more being forced to write 5 overloads of a contructor that just accepts these variables and assigns them to fields.This syntax works for both public fields and properties.


In case the class contains other classes as fields then the same statement can also initialize the contained class (see code below in bold).

class Phone

{

public int countryCode;

public int areaCode;

public int number;

}

class Customer

{

public string name;

public string address;

public Phone phone;

}

static void Main(string[] args)

{

var cust = new Customer{name = “Abhinaba Basu”,
address =
“1835 73rd Ave NE, Medina, WA 98039”,

phone = new Phone {countryCode = 1, areaCode = 425,
number = 9999999}};

}


This piece of code is equivalent to the following C#2.0 code

Customer customer = new Customer();

customer.name = “Abhinaba Basu”;

customer.address = “1835 73rd Ave NE, Medina, WA 98039”;

Phone __phone = new Phone();

__phone.countryCode = 1;

__phone.areaCode = 425;

__phone.number = 9999999;

customer.phone = __phone;


Collection Initializers


Collection initializer is a natural extension to object initializer. It consists of a list of initilializer for each of the elements in a collection seperated by comma and encosed in {}. For a simple List<int> it is as follows

List<int> digits = new List<int> { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };


For the Customer and Phone number class discussed above the collection initializer will look like

List<Customer> custList = new List<Customer> {

new Customer {

name = “Samrat”, address = “NJ, USA”,

phone = new Phone {countryCode = 91, areaCode = 999, number = 8888888}

},

new Customer {

name = “Kaushik”, address = “Behala, Kolkata”,

phone = new Phone {countryCode = 91, areaCode = 33, number = 3333333}

},

new Customer {

name = “Rahul”, address = “Kerala”,

phone = new Phone {countryCode = 91, areaCode = 00, number = 4444}

}

};


Just trying to write the above piece of code in C#2.0 syntax shows how cool this new feature is.


Why I love this


This feature reduce typing a lot and will go a long way in helping reduce carpal tunnel syndrome :^)


Moreover, it is very intuitive, so much so that people will start using this even without figuring out that this was not present before and they were required to allocate the collection and then individually allocate and add each item to the collection. Just after using it for a couple of days I am badly missing it in C#2.0. I just can’t figure out why this was not considered for 2.0. I can guess why but I’ll still complain :)

Comments (29)

  1. Patrick says:

    Ok, now this I like! Forget lambda functions, continuation, and all that other jazz. This is a feature that will save keystrokes, that is intuitive, and that instantly makes sense to all C# developers!

    Let’s see more stuff like this that everyone can benefit from!

  2. jeff says:

    This looks cool, though is it just limited to public fields? Setting properties would be nice.

    Does this only work if there is no default constructor for an object?

  3. tzagotta says:

    This is a really nice addition!

    It would be nice to get a CTP preview release add-in for VS2005 for some of these C# 3.0 features. It will be too hard to wait 2-3 years until the next release!

  4. Victor says:

    The collection initializer is nice, but you can do something similar in C# 2.0 with only a little bit more work. For example, your sample would look like:

    List<int> digits = new List<int> (

    new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

  5. CN says:

    Am I correct in assuming that any "readonly" fields will not be accepted in the initalizer, as I guess it’s just syntactic sugar? This means you’ll still need the different constructors for types where it has to be immutable, for example simple struct containers, where this would otherwise be a very nice syntax.

  6. zz says:

    What happens when Customer does not have a default constructor. Does it allow something like this?

    var cust = new Customer( init1, init2 ) // <- Non-default constructor

    {name = "Abhinaba Basu", address = "1835 73rd Ave NE, Medina, WA 98039", Age = 99 };

  7. abhinaba says:

    The answer to each of the questions above

    Q. Are properties supported (Jeff)

    A. Yes they are. To illustrate this I specifically added Age as a property in Customer class

    Q. Does this only work if there is no default constructor for an object (jeff)

    A. This has nothing to do with presense of ctor. Lets see the following example where there is a ctor and you invoke both the ctor as well as use the initializer syntax

    class Item

    {

    private int m_itemId;

    private string m_itemName;

    public Item(int itemId, string itemName)

    {

    m_itemId = itemId;

    m_itemName = itemName;

    }

    public string description;

    }

    Item item = new Item (12, "Football") { description = "Size 4 footbal" } ;

    Q. C#2.0 (or 1.0) already had some thing like

    List<int> digits = new List<int> (

    new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }); (victor)

    A. Well yes, this is ok with value types. For reference types you can allocate the objects and then add them in one statement, either as above or using List<>.AddRange. But you had to manage the intermediate variables to store inidividual items. There was no way to do the whole thing in one statement. So effectively with this new syntax value and reference type collection initialization is becoming the same.

    Q.Does it work with Readonly fields (CN)

    A. You are right this is just syntactic sugar and hence will not work with readonly fields.

    Q. What happens with non-default ctor (zz)

    A. You are absolutely right it works just as you thought. See the sample in this comment

  8. Great blog says:

    Your blog is really very interesting.

  9. Samuel says:

    This just looks like a crippled version of the VB "With" syntax. Its really bad the C# programmers had to live without stroke savers like this so long ….

  10. mhp says:

    For those who has worked with VB will find this feature still incomplete. If we are talking about C# 3.0 you should seriously consider implementing "With" keyword as supported in VB. In that case C# 3.0 code may look like following:

    With (customer = new Customer()){

        .name = "Abhinaba Basu";

        .address = "1835 73rd Ave NE, Medina, WA 98039";

        .Age = 99;

    }

    IMHO, the feature you described does very little as far as readability has cocerned, beside that it only supported in constructor. However if you implement "With" keyword, it will have more than one advantages:

    1. You can use it anywhere (not limited to constructor)

    2. CLR/JIT can omptimize performance

    3. More readable

  11. Kazi says:

    The collection initializer is not working with Dictionary<TKey, TValue>, any chance for a fix?

  12. abhinaba says:

    Kazi, can you post any code snippet of what exactly is not working? I’ll try to get you an answer

  13. Kazi says:

    A simple sample for generic Dictionary objects trying to initialize with collection initializers (compiler error messages inculded):

    // Error: Cannot implicitly convert type ‘string’ to ‘System.Collections.Generic.KeyValuePair<string,int>’

    var dict1 = new Dictionary<string, int>() {"one", 1};

    // Error: No overload for method ‘Add’ takes ‘1’ arguments

    var dict2 = new Dictionary<string, int>() {new KeyValuePair<string, int>("one", 1)};

  14. In my last post&amp;nbsp;I had discussed about anonymous methods.

    I had used the following code snippet…

  15. MZ says:

    I got here looking for information similar to CNs… and am dissappointed.  Are there any plans to make "immutable" objects less painful?  

    Right now there is no easy way to say "Copy X but with changed properties X.A and X.B".  Being able to designate a field or property as "Initializable" instead of "ReadOnly" to allow immutable functionality would make things less painful.

    Imagine being able to say

    myFont = new Font(myFont){Size = 8}

    instead of

    myFont = new Font(

            myFont.FontFamily,

            8,

            myFont.Style,

            GraphicsUnit.Point,

            myFont.GdiCharSet,

            myFont.GdiVerticalFont

    );

    Theoritically one can do similar functionality with tons of heavily overloaded codegenned constructors, but even that falls apart if you have multiple properties with the same type.

  16. This is the my fourth post in the series of posts I am making on C#3.0. See the previous posts here, here&nbsp;and here

    I do not agree. Go to http://www.hotelsstore.info/liar_France/ocellus_Nord%20Pas%20de%20Calais/explicatory_Lille_1.html

  17. For tabs, you can do this

    int[] tab = { 1, 2, 3};

  18. This is the my fourth post in the series of posts I am making on C#3.0. See the previous posts here, here&nbsp;and here

    I do not agree. Go to http://www.greatjobz.info/bronchi_Italy/invulnerability_Toscana/dobbin_Florence_1.html

  19. How not to use ASP.AJAX – Pt 2

  20. Noch mehr Schreibarbeit spart man zusätzlich mit den Collection Initializers, die so ähnlich wie die

  21. In my last post I had discussed about anonymous methods. I had used the following code snippet to show

  22. RNEELY says:

    Kazi, Try this:

    static void Main(string[] args)

    {

    Dictionary<string, int> MyMap = new Dictionary<string, int>()

    { { "one", 1 }, { "two", 2 }};  

    Console.WriteLine("one is {0}", MyMap["one"].ToString());

    Console.WriteLine("two is {0}", MyMap["two"].ToString());

    }

  23. ajay_ndelhi says:

    Thank for putting it so nicely.

  24. Spike says:

    QUOTE —————————————-

    Saturday, September 17, 2005 1:27 PM by jeff

    This looks cool, though is it just limited to public fields? Setting properties would be nice.

    ———————————————-

    Idiot, read the article first, before you post next time.

    Third line:

    QUOTE —————————————–

    if I wanted to create a object of the type customer and fill up the public VARIABLES and P R O P E R T I E S then in C#2.0 I need to do something like….

    ———————————————-

  25. Furqan Khan says:

    HAHA! Yes, you are pretty stupid to ask that question. The article shows you in the first line of the first code example how to make it work for properties.

    lol@u wtf

  26. I've been using the heck outta this feature. almost too much 😉