While working with the new Visual Studio .NET 2008 I'm using more and more the new features that are available in Visual Studio .NET and C# compile options. One of those features are object and collection initializers. I like it to write source code like following lines (I always have my JavaScript code in mind, which is sometimes very similar):
FeedItem o = new FeedItem {
Title = "hans",
Published = DateTime.Now,IsCool = <span class="kwrd">true</span>, <br> NumComments = 10 <br> };
<span class="kwrd">string</span>[] o = <span class="kwrd">new</span> <span class="kwrd">string</span>[] { <span class="str">"michael"</span>, <span class="str">"schwarz"</span> };</pre>
The last line I can write as following line, too:
<pre class="csharpcode"><span class="kwrd">string</span>[] o = { <span class="str">"michael"</span>, <span class="str">"schwarz"</span> };</pre>
Wow, that's great. But what about following line?
<pre class="csharpcode">List<<span class="kwrd">string</span>> o = { <span class="str">"michael"</span>, <span class="str">"schwarz"</span> };</pre>
Hm, this will fail with an (not very clear) compiler error, strange. I often use the generic List interface, and that would be nice to write.
How is it working?
Type inference for assignments in the C# 3.0 compiler goes from right-to-left (types on the left side of an assignment are inferred from the expression on the right).
Unless the compiler can figure out what kind of initializer you're trying to use just from the expression on the right, it may not be able to do what you intended, even if you specified an explicit type on the left.
The array case
<pre class="csharpcode"><span class="kwrd">string</span>[] o = { <span class="str">"michael"</span>, <span class="str">"schwarz"</span> }; </pre>
This works because the inferred type of { "michael", "schwarz" } is an array of the best type (in this case string). The resulting string array can be assigned to the string[] local o.
The list case
<pre class="csharpcode">List<<span class="kwrd">string</span>> o = { <span class="str">"michael"</span>, <span class="str">"schwarz"</span> }; </pre>
Here, the compiler looks at the right side of the assignment and sees what looks like an array initializer, and complains that you cannot assign an array to a List<string> variable. You must specify the "new List<string>" for this to be treated as a list initializer instead. The same issue arises in the nested List case with List<List<int>> o = { { 1, 2, 3, 4 }, { 55, 44, 33, 22, 11 } };.
Array of arrays vs. rectangular array
<pre class="csharpcode"><span class="kwrd">int</span>[][] o = { { 1, 2, 3 } }; </pre>
In this case, the 2-level array initializer on the right is actually creating a 2-dimensional rectangular array (of type int[,]), instead of a jagged array of arrays (of type int[][]). The compiler is not letting you assign a value of type int[,] to a local of type int[][]. If you change your code to the following it compiles:
<pre class="csharpcode"><span class="kwrd">int</span>[,] o = { { 1, 2, 3 } }; </pre>
Alex Turner said: "I do agree that the error message for this situation is misleading (it tells you to use the array initializer in a variable initializer, which it looks like you are!), and we may consider a fix for this message in the next version of the compiler. We've tried to balance the safety benefits of static typing with the simplicity of type inference for C# 3.0. This is one of the areas where you can run into some issues, but we hope for the most part the error messages will guide users in the right direction."
I hope that helps if you get into the same issue trying the great object and collection initializers in Visual Studio .NET 2008.