int[] a = new int[5];
string[] b = new string[1];
The types of both a
and b
inherit from the abstract System.Array
, but there is no real classes in the built-in library(it seems that there are some runtime types, you can't find the type defination class of an int[]
). Can you tell me what happens while compiling? And why did they(the c# team) make this design(I mean why it's not something like Array<T>
,instead they are using an abstract class with compiler magics)?
Look at the
Array
class.When declaring an array using the
[]
syntax, the compiler, behind the scenes will use this class for you.For C#,
[]
becomes a type that inherits fromSystem.Array
.From the C# 4.0 spec:
Generics are ideal for defining a container, as they constrain the element type so you can't insert type A and try to retrieve type B.
But generics were not added until CLR2/C#2. So arrays had to provide type safety in their own way.
Even so, it's not that different to generics. You note that there is no special class for
int[]
. But nor would there be forArray<int>
. In generics there would only be the generic classArray<T>
, and the CLR "magically" creates specialised versions for distinct type argument you use. So it would be no less "magic" if generics were used.Despite this, in the CLR the type of any object is reified (it exists as a value you can manipulate), of type
Type
, and can be obtained withtypeof
. So although there is no code declaration of any array type (and why would you need to see it?) there is aType
object that you can query.By the way, there was a design flaw in the way arrays constrain element types. You can declare an array:
You can then store it in a looser variable:
But that means you can insert a string (at least it appears so at compile time):
At runtime it throws an exception. The idea of static type checking is to catch this kind of thing at compile time, not runtime. Generics would not have had this problem because they don't give assignment compatibility to generic class instances based on the compatibility of their type parameters. (Since C#4/CLR4 they have gained the ability to do that where it makes sense, but that wouldn't make sense for a mutable array.)
Trying to reason this out within the .NET type system doesn't get you very far. There is core support built into the JIT compiler and the CLR to deal with creating arrays. A statement like this:
Generates this IL:
Which the JIT compiler then translate into this machine code:
Core ingredients here are the dedicated IL opcode, newarr, instead of the usual newobj opcode that creates an instance of a class. And the simple translation to a CLR helper function that actually gets the object created. You can have a look-see at this helper function with the SSCLI20 source code,
clr\src\vm\jithelpers.cpp
. Too large to post here, but it is heavily optimized to make this kind of code run as fast possible, having direct access to the type internals available to CLR code.There are two of these helpers available, JIT_NewArr1() creates one-dimensional (vector) arrays and JIT_NewMDArr() creates multi-dimensional arrays. Compare to the two overloads available for Type.MakeArrayType().
There is such class. You cannot inherit it, but when you write "int[]" the compiler creates a type that inherits System.Array. So if you declare a variable:
This variable will have a type that inherits System.Array, and therefore has all its methods and properties.
This is also similar to delegates. When you define a delegate:
Then the type
Foo
is actually a class that inheritsSystem.MulticastDelegate
andBar
is a class that inheritsSystem.Delegate
.Arrays are special to CLR. They're allocated with 'newarr' instruction, and elements are accessed with 'ldelem*' and 'stelem*' instructions, not via System.Array methods;
see http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.newarr.aspx
You can check out ildasm output to see how arrays are represented.
So, to answer your question - no new type declaration is generated for any particular array.
I went digging through the ECMA 335 spec, so I figured I'd share what I read.
It goes on to state, quite verbosely, that the methods supplied are:
VES means Virtual Execution System, and the CLR is an implementation of it.
The spec also details how to store the data of the array (contiguously in row-major order), what indexing is allowed in arrays (0-based only), when a vector is created (single dimensional, 0-based arrays) as opposed to a different array type, when the CIL instruction
newarr
is used as opposed tonewobj
(creating a 0-based, single dimensional array).Basically everything that the compiler has to do to build the method lookup tables etc.. for a regular type, it has to do for arrays, but they just programmed a more versatile and slightly special behavior into the compiler / JIT.
Why did they do it? Probably because arrays are special, widely used, and can be stored in an optimized fashion. The C# team did not necessarily make this decision though. It's more of a .NET thing, which is a cousin to Mono and Portable.NET, all of which are a CIL thing.