in Development

C# 3.0 – Object and Collection Initializers

With C# 3.0 you can initialize objects specifying the values of their visible properties and/or fields enclosed between brackets. The syntax is as easy as open the brackets and provide a list of name/value pairs separated by commas with all the properties/fields you want to initialize, the value of the field can be an expression or another initializer. Consider that using an object initializer without using the parenthesis of the constructor, is equivalent to invoking the default constructor. Next you a sample of how to initialize the same class with different styles.

   1: // Old Style
   2: Cookie cookie = new Cookie();
   3: cookie.Name = "MyCookie"
   4: cookie.Value = "Jose"
   5: cookie.Comment = "a cookie" 
   6:  
   7: // With Object initializer
   8: var cookie2 = new Cookie() { Name = "MyCookie", Value = "Jose", Comment = "a cookie" }; 
   9:  
  10: // Combining non default constructor and Object Initializer
  11: var cookie3 = new Cookie("MyCookie", "Jose") { Comment = "a cookie" }; 

Collection initializers allow us adding elements to a collection in a similar way we do in array initializers. The initializer consists of the list of elements we want to add separated by commas and enclosed by brackets. The elements can be single values or other initiliazers, but unlike object initializers they don’t allow expressions to avoid confuse them. Below you can see some samples:

   1: // Collection Initializer
   2: var list = new ArrayList { "a", 1, "b"}; 
   3:  
   4: // Initialize collection that has Add method with more than one parameter
   5: var hash = new Hashtable { { 1, "one" }, { 2, "second" }, { 3, "third" } }; 
   6:  
   7: // Collection Initializer combined with Object Initializer
   8: var cookies = new List<Cookie> { new Cookie("cookie1", "1"), new Cookie("cookie2", "2") }; 

If you build your own collection, there are some requirements that the class must satisfy in order users can take profit of Collection Initializers. The class must implement the IEnumerable interface and must have at least one public "Add" method. Look the next code:

   1: static void Main(string[] args)
   2: {
   3:     Numbers numbers = new Numbers { 1, 2, 3, 4 }; 
   4:  
   5:     foreach (var n in numbers)
   6:     {
   7:         System.Console.WriteLine(n);
   8:     }
   9:     
  10:     System.Console.ReadKey();
  11: }
  12:  
  13: public class Numbers : System.Collections.IEnumerable
  14: {
  15:     List<int> numbers = new List<int>();
  16:  
  17:     public System.Collections.IEnumerator GetEnumerator()
  18:     {
  19:         foreach (int i in numbers)
  20:         {
  21:             yield return i;
  22:         }
  23:     }
  24:  
  25:     public void Add(int number)
  26:     {
  27:         numbers.Add(number);
  28:     }
  29: }

If you change the modifier of the method "Add" to private, the compiler will give the error "Numbers.Add(int) is inaccessible due to its protection level". This gives the hint that the compiler translates the Collection Initializer syntax to as much calls to the matching method Add as elements you add. We can verify it just examining the IL code.

IL_0000: newobj instance void Demo.Numbers::.ctor()

IL_0005: stloc.2

IL_0006: ldloc.2

IL_0007: ldc.i4.1

IL_0008: callvirt instance void Demo.Numbers::Add(int32)

IL_000d: ldloc.2

IL_000e: ldc.i4.2

IL_000f: callvirt instance void Demo.Numbers::Add(int32)

IL_0014: ldloc.2

IL_0015: ldc.i4.3

IL_0016: callvirt instance void Demo.Numbers::Add(int32)

IL_001b: ldloc.2

IL_001c: ldc.i4.4

IL_001d: callvirt instance void Demo.Numbers::Add(int32)

IL_0022: ldloc.2