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
whoseName
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!
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.
See more on this question at Stackoverflow