C#: Array and collection intializers

I was recently asked few questions about array and collection intializers in C#. Because it may be useful for others as well, I decided to write the answer down in this form.

All information below is valid for C# in version 3.0 or higher.

Arrays

A single-dimensional array is normally declared and initialized this way:

string[] array = new string[3]; //Array of three strings

Values are assigned simply by writing to particular indexes:

array[0] = "alpha";
array[1] = "bravo";
array[2] = "charlie";

Array initializer allows to write the whole aforementioned code in a single command:

string[] array = new string[3] {"alpha", "bravo", "charlie"};
var array = new string[3] {"alpha", "bravo", "charlie"}; //Alternative using implicitly typed variable

The initializer always creates an array with the same number of elements as defined in curly brackets, so no other number than three may be entered in the previous example. Therefore the number of elements doesn’t have to be specified at all.

var array = new string[] {"alpha", "bravo", "charlie"}; //Compiler knows to create an array with three elements

C# allows to further simplify this command since compiler is able to infer the type of array from types used in the initializer, so you don’t have to specify the type of array either.

var array = new[] {"alpha", "bravo", "charlie"}; //Array of strings
var array = new[] {"alpha", "bravo", new Object()}; //Array of objects
var array = new[] {"alpha", "bravo", 'c'}; //Error - "No best type found for implicitly-typed array"

In the last case, compiler would have to box the ‘c’ character to object and create an array of objects, which it prefers not to do automatically. You can solve it easily be specifying the type of array.

You can take simplifying even farther and omit even the new[] operator – compilator knows that the output of the initalizer will be an array. But you can’t – in the same time – declare the variable as var and let compiler to infer its type.

string[] array = {"alpha", "bravo", "charlie"}; //OK
var array = {"alpha", "bravo", "charlie"}; //Not allowed

Furthermore, this syntax can be used only when declaring a local variable or a field, you can’t use it when defining a method argument, for example.

String.Concat( {"a", "b"} ); //Not allowed
String.Concat( new[] {"a", "b"} ); //OK

Multi-dimensional arrays work similarly to single-dimensional ones:

string[,] array =
{
    {"a", "b"},
    {"c", "d"}
}

Nevertheless, the same initializer can’t be used for “jagged” arrays (arrays of arrays); you have to create inner arrays by the new operator.

string[][] array =
{
    new[] {"a", "b"},
    new[] {"c", "d"}
}

Collections

A similar support for element initalization is available for all collections – better said, all types implementing the IEnumerable interface and providing public Add method. You have to always call collection’s constructor, but you can just add values in curly brackets instead of calling Add.

var list = new List<string>() { "alpha", "bravo", "charlie" };

You can omit parentheses  if calling a parameterless constructor.

var list = new List<string> { "a", "b", "c" };

But you can also use parametrized constructors – the following example creates a new instance with elements from an existing collection and add more elements in the initializer.

var list2 = new List<string>(list) { "d", "e" };
list2.ForEach( s => Console.Write(s)); //Displays "abcde"

If the Add methods has multiple parameters, they need to be enclosed in additional curly brackets. The following code adds two elements to a dictionary.

var dict = new Dictionary<int, string>
{
    { 1, "alpha" },
    { 2, "bravo" }
};

Every item in an initializer may even use a different overload of Add method, if available. For example, NameValueCollection (from System.Collection.Specialized namespace) offers methods Add(String, String) and Add(NameValueCollection). Initializer nvc2 of variable uses both:

NameValueCollection nvc1 = new NameValueCollection { {"a", "b"} };
NameValueCollection nvc2 = new NameValueCollection
{
    {"c", "d"},
    nvc1
};

Although initializers provides nothing what couldn’t be written by other means, they allow for writing shorter and more readable code – and that’s not negligible.