Why does C # behave differently on the two syntaxes of an int array

An array in C # implicitly refers to a reference type:

object[] listString = new string[] { "string1", "string2" }; 

But not by type of value, so if you change string to int , you will get a compiled error:

 object[] listInt = new int[] {0, 1}; // compile error 

Now the problem is that you declare an int array as two syntaxes, below which the int type is not explicitly declared, just differentiate only with new[] , the compiler will handle it differently:

 object[] list1 = { 0, 1 }; //compile successfully object[] list2 = new[] {0, 1}; //compile error 

You will get object[] list1 = { 0, 1 }; compiled successfully, but object[] list2= new[] {0, 1}; compiled error.

C # compiler seems to be considering

 object[] list1 = { 0, 1 }; 

but

 object[] list1 = new object[]{ 0, 1 }; 

but

 object[] list2 = new[] { 0, 1 }; 

but

 object[] list2 = new int[]{ 0, 1 }; //error because of co-variant 

Why does the C # compiler behave differently in this case?

+69
arrays c #
May 09 '13 at 8:00
source share
6 answers

The version that compiles uses an array initializer to initialize list1 . C # Language Specification, §1.110 ("Array Initializers"):

An array initializer consists of a sequence of variable initializers enclosed by "{" and "}" tokens and separated by "," tokens. each variable initializer is an expression or, in the case of a multidimensional array, an initializer of a nested array.

The context in which the array initializer is used determines the type of array being initialized. In an array creation expression, the array type immediately precedes the initializer or is inferred from the expression in the array initializer. In a field or variable declaration, an array type is the type of field or variable that is declared.

When an array initializer is used in a field or variable declaration, for example:

 int[] a = {0, 2, 4, 6, 8}; 

this is just a contraction of the array creation conditional expression:

 int[] a = new int[] {0, 2, 4, 6, 8}; 

So, obviously, this should compile.

The second version uses an explicit expression to create an array, where you instruct the compiler specifically what type of array to create. §1.51.10.4 ("Expressions for creating an array"):

An expression to create an array of a third form is called an implicitly typed array creation expression. This is similar to the second form, except that the type of the array element is not explicitly specified, but defined as the best general type (§1.50.2.14) of the set of expressions in the array initializer.

Therefore, the second version is equivalent

 object[] list2 = new int[] { 0, 1 }; 

So now the question now becomes “why can't I assign int[] to object[] ”, as you mentioned at the end of the question. And the answer is also simple, given in §1.109 ("Array covariance"):

The covariance of arrays does not specifically apply to arrays of value types. For example, no conversion exists, which allows int[] to process object[] .

+57
May 09 '13 at 8:23
source share

Ad

 object[] listInt = new int[] {0, 1}; 

invalid because covariant array conversions are not allowed for value types (and int is a value type). Alternatively, declaration

 object[] listInt = new string[] {"0", "1"}; 

is valid because covariant array conversions are allowed for reference types. This is because the assignment x = (object)myString includes a simple assignment, but y = (object)myInt requires a box operation.

Now about the differences between the two ads. In the declaration of object[] list2 = new[] { 0, 1 } due to how type inference works, he first looks at the expression of the right hand and concludes that new[] { 0, 1 } should be considered as new int[] { 0, 1 } . Then he tries to assign this int array to an array of objects, indicating an error due to covariant conversion of value types. The declaration object[] list1 = { 0, 1 } , however, uses the collection initializer, and in these circumstances the type of the collection is determined where this type is defined, so each item will be replaced with the type expected by the collection.

+27
May 9 '13 at 8:14
source share

When you use { and } , you use collection initializers (see http://msdn.microsoft.com/en-us/library/vstudio/bb384062.aspx ). The values ​​between these brackets should be placed somewhere. Therefore, a collection must be created. The compiler will analyze the context to find out which collection.

In the case of the first: object[] list1 = { 0, 1 }; it is clear that a set must be created. But what should it be? There is no new operation. There is only one hint: list1 is of type object[] . Thus, the compiler creates this collection and fills it with characters.

In your second example, object[] list1 = new[] { 0, 1 }; There is another hint: new[] . And this hint explicitly says: “There will be an array. This array has no type, so it will try to find the type of the array by anaylizing the values. They are all int , so it will create an int array and fill it. Another hint object[] completely ignored because the hints creation is much more important than the hints to which it should be assigned.Now the compiler wants to assign this array to list1 and BOOM: it does not fit!

+10
May 9 '13 at 8:09
source share

Operator object[] list1 = { 0, 1 }; compiles because the compiler is smart enough to know that you are trying to convert an array of numeric types into an array of a reference type, so it puts Int32 elements in reference types.

You can also explicitly specify a primitive type:

object[] list2 = Array.ConvertAll<int, Object>(new[] { 0, 1 }, input => (Object)input);

The compiler will not implicitly do boxing for you if you specify 'int []' or 'Int32 []' as an array type, but it looks like it could be added in C #.

+2
May 09 '13 at 8:40
source share

An array initializer is a compiler convenience. If I say, “I declare an array of objects and assign a value to it,” it makes sense for the compiler to assume that your { 0, 1 } is an array of objects and interpret it as such. Although the syntax seems to be the purpose, it is not: you are using an initializer. The duration of this syntax is object[] list1 = new object[] { 0, 1 }

When you say new[] { 0, 1 } , it is an expression that creates an array and initializes it. This expression is evaluated no matter what you assign it to, and since the compiler detects implicit integer typing, it creates an int[] . The top version of this expression is object[] list2 = new int[] { 0, 1 }

If you compare versions with long versions of these two statements, it is clear where they differ.

+1
May 09 '13 at 8:13
source share
 object[] listInt = new int[] {0, 1}; 

is short for

 object[] listInt; listInt = new int[] {0, 1}; 

which does not work because int[] not covariant with object[] .

And when you say new[] , it is equivalent to new int[] , therefore, the same applies.

+1
May 9 '13 at 8:44
source share



All Articles