Vectors and Arrays
In .Net there are two flavors of arrays: vectors (ELEMENT_TYPE_SZARRAY) and arrays (ELEMENT_TYPE_ARRAY).
Vectors: single-dimensional arrays with a zero lower bound.
Arrays (or MDArray): Multidimensional arrays (arrays that may have multiple dimensions or may have a non-zero lower bounds).
An interesting note on arrays (from page 149 of Serge Lidin's book):
Both array types are constructed types, so neither of them has an associated .NET Framework type. All vectors and arrays are objects (class instances ) derived from the abstract class [mscorlib]System.Array.
CLR via C#, Chapter 13 is also a good reference to the details of Arrays. According to Richter (page 297):
Vectors give the best performance because you can use specific IL instructions - such as newarr, ldelem, ldelema, ldlen, and stelem - to manipulate them. ... Zero-based, single-dimensional jagged arrays have the same performance as normal vectors. However, accessing the elements of a jagged array means that two or more array accesses must occur.
Example of a single dimensional array (vector or szarray):
private string[] stringVector = new string[10];
Example of multi-dimensional array (mdarray):
private string[,] stringMDArray = new string[10,10];
Example of single-dimensional jagged array:
private string[][] stringJaggedArray = new string[10][];
Signatures
Vectors are encoded in the following format: ELEMENT_TYPE_SZARRAY
NOTE: The size is not part of the encoding (like you might expect it to be) - this is because when the newarr IL instruction creates the instance of the array the size is provided at that time.
[Multidimensional] Arrays are encoded in the following format (taken from Serge Lidin's book on page 149)
ELEMENT_TYPE_ARRAY......
where the following is true:
cannot be void
is the number of array dimensions (K>0)
is the number of specified sizes for dimensions (N <= K)
is an unsigned integer specifying the size (n = 1, ..., N)
is the number of specified lower bounds (M <= K)
is a signed integer specifying the lower bound (m = 1, ..., M)
The following diagram is taken from the Ecma 335 spec, Partition III, page 161:
A nice note under the ArrayShape in the spec is "Note: definitions can nest, since the Type can itself be an array"
Example 22: Decoding a field signature of a string array (vector)
C# Code:
private string[] szarray1;
Field Information from ILDasm:
0x06 = IMAGE_CEE_CS_CALLCONV_FIELD
0x1d = ELEMENT_TYPE_SZARRAY
0x0e = ELEMENT_TYPE_STRING
This tells us the field is an string single dimensional array.
Example 23: Decoding a field signature of an int array (vector)
C# Code:
Field Information from ILDasm:
0x06 = IMAGE_CEE_CS_CALLCONV_FIELD
0x1d = ELEMENT_TYPE_SZARRAY
0x08 = ELEMENT_TYPE_I4
This tells us the field is an int single dimensional array.
Example 24: Decoding a field signature of an array of objects declared in current assembly (vector)
C# Code:
private TestClass[] szarray3;
Field Information from ILDasm:
0x06 = IMAGE_CEE_CS_CALLCONV_FIELD
0x1d = ELEMENT_TYPE_SZARRAY
0x12 = ELEMENT_TYPE_CLASS
0x08 TypeDefRefEncoded token

0x08 is also compressed, but is the same either compressed or not

Determine the table the type is in:
Neither of the last 2 bits or on (00 = TypeDef)
Get the index of the record:
Bit shift to the left by 2 and you get 2 (0x02) - which is the index in the TypeDef table for the SignatureUtility.TestClass record.
This tells us the field is a single dimensional array of type SignatureUtility.TestClass
Example 25: Decoding a field signature of an multi-dimensional array of strings
C# Code:
private string[,] etarray1;
Field Information from ILDasm:
0x06 = IMAGE_CEE_CS_CALLCONV_FIELD
0x14 = ELEMENT_TYPE_ARRAY
0x0e = ELEMENT_TYPE_STRING (type the array holds = System.String)
0x02 = Rank (compressed, but the same as it being uncompressed) or number of dimensions = 2
0x00 = Number of sizes (also compressed/uncompressed) - no sizes provided in declaration = 0
0x02 = Number of lower bounds (compressed integer) = 2
0x00 = First dimension's lower bound = 0
0x00 = Second dimension's lower bound = 0
This tells us the field is a multidimensional array of type string, that was declared with no sizes and has the lower bounds of 0 for the first dimension and 0 for the second dimension. Which is what ILDasm shows for this field in its tree view:
Example 26: Decoding a field signature of an multi-dimensional array of integers
C# Code:
Field Information from ILDasm:
0x06 = IMAGE_CEE_CS_CALLCONV_FIELD
0x14 = ELEMENT_TYPE_ARRAY
0x08 = ELEMENT_TYPE_I4 (type the array holds = System.Int32)
0x02 = Rank (compressed, but the same as it being uncompressed) or number of dimensions = 2
0x00 = Number of sizes (also compressed/uncompressed) - no sizes provided in declaration = 0
0x02 = Number of lower bounds (compressed integer) = 2
0x00 = First dimension's lower bound = 0
0x00 = Second dimension's lower bound = 0
This tells us the field is a multidimensional array of type int, that was declared with no sizes and has the lower bounds of 0 for the first dimension and 0 for the second dimension. Which is what ILDasm shows for this field in its tree view:
Example 27: Decoding a field signature of an multi-dimensional array of an object declared in the same assembly
C# Code:
private TestClass[,] etarray3;
Field Information from ILDasm:
0x06 = IMAGE_CEE_CS_CALLCONV_FIELD
0x14 = ELEMENT_TYPE_ARRAY
0x12 = ELEMENT_TYPE_CLASS
0x08 TypeDefRefEncoded token

0x08 is also compressed, but is the same either compressed or not

Determine the table the type is in:
Neither of the last 2 bits or on (00 = TypeDef)
Get the index of the record:
Bit shift to the left by 2 and you get 2 (0x02) - which is the index in the TypeDef table for the SignatureUtility.TestClass record.
0x02 = Rank (compressed, but the same as it being uncompressed) or number of dimensions = 2
0x00 = Number of sizes (also compressed/uncompressed) - no sizes provided in declaration = 0
0x02 = Number of lower bounds (compressed integer) = 2
0x00 = First dimension's lower bound = 0
0x00 = Second dimension's lower bound = 0
This tells us the field is a multidimensional array of type SignatureUtility.TestClass (declared in the same assembly), that was declared with no sizes and has the lower bounds of 0 for the first dimension and 0 for the second dimension. Which is what ILDasm shows for this field in its tree view:
Next notes will provide:
- Overview of Method Signatures (MethodDefSig, MethodRefSig)
- Start out with some easy examples