Array types with same element type & rank not equal

Very simple:

var equal1 = typeof(object[]) == typeof(object).MakeArrayType();
var equal2 = typeof(object[]) == typeof(object).MakeArrayType(1);
var equal3 = typeof(object[,]) == typeof(object).MakeArrayType(2);

The assumption is that all three should be true, but it turns out that equal2 is false - which doesn't really make sense given that the first two MakeArrayType calls are equivalent and the resulting array types are the same.

The only difference I can actually discern is that explicitly passing the rank of the array type as '1' yields a Type whose Name is "Object[*]" whereas omitting it yields "Object[]".

So I thought, perhaps the rank of object[] isn't 1 (even though it clearly is!) - so I did this:

var type1 = typeof(object[]);
var type2 = type1.GetElementType().MakeArrayType(type1.GetArrayRank());
var equal = type1 == type2; //false

The types now definitely have the same rank, but are not equal.

This scenario is more like my current scenario as I try to build Array covariance into Rezolver - so I'm recomposing array types by walking base hierarchies and using MakeArrayType with the original array type's rank.

So - can anyone explain why two array types with identical rank are not considered equal?

I realise there's likely some nuance I'm missing here, and that there are workarounds I can use, I'm just curious as to what's going on!

Jon Skeet
people
quotationmark

The documentation explains the difference:

The common language runtime makes a distinction between vectors (that is, one-dimensional arrays that are always zero-based) and multidimensional arrays. A vector, which always has only one dimension, is not the same as a multidimensional array that happens to have only one dimension. You cannot use this method overload to create a vector type; if rank is 1, this method overload returns a multidimensional array type that happens to have one dimension. Use the MakeArrayType() method overload to create vector types.

So basically, equal1 returns a vector, and equal2 returns a multidimensional array that happens to have a rank of 1.

The two types are treated very differently in the CLR.

Interestingly, if you create an instance of the type, you end up with a vector again:

var type = typeof(object).MakeArrayType(1);
// Create an instance with length 2
var array = Activator.CreateInstance(type, 2);
Console.WriteLine(array.GetType());            // System.Object[]
Console.WriteLine(type);                       // System.Object[*]

Array.CreateInstance shows the same behaviour: if you ask for an array with a lower bound of 0 and rank 1, it will always create a vector:

var array = Array.CreateInstance(typeof(object), new[] { 2 }, new[] { 0 });
Console.WriteLine(array.GetType());
object[] objArray = (object[]) array; // This is fine

If you change the 0 to any non-zero value, it will create a System.Object[*] and the cast will fail.

people

See more on this question at Stackoverflow