具有相同元素类型和秩的数组类型不相等

14

非常简单:

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

假设所有三个条件都是正确的,但结果发现equal2false,这似乎没有意义,因为前两个MakeArrayType调用是等价的,得到的数组类型也相同。

我实际上能够分辨出的唯一区别是,显式传递数组类型的秩为 '1' 会产生一个Type,其Name"Object[*]",而省略它则产生"Object[]"

所以我想,也许object[]的秩不是1(尽管它显然是!)- 所以我做了这个:

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

这些类型现在明确具有相同的等级,但不相等。

这种情况更像是我目前的场景,我试图将数组协变性嵌入Rezolver中 - 因此,我通过遍历基本层次结构并使用MakeArrayType及原始数组类型的等级来重新组合数组类型。

那么,有人能解释为什么具有相同等级的两个数组类型不被视为相等吗?

我意识到可能有一些微妙之处我还没有理解,也可以使用一些解决方法,只是好奇发生了什么!

1个回答

21

文档解释了区别:

公共语言运行库在向量(即始终为零的一维数组)和多维数组之间进行区分。始终只有一个维度的向量与恰好只有一个维度的多维数组不同。 不能使用此方法重载创建向量类型;如果秩为1,则此方法重载返回恰好只有一个维度的多维数组类型。 使用MakeArrayType()方法重载创建向量类型。

所以,equal1返回向量,而equal2返回具有秩为1的多维数组。

这两种类型在CLR中的处理方式非常不同。

有趣的是,如果创建该类型的实例,您将再次得到向量:

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 的行为相同:如果您请求一个下边界为0且秩为1的数组,它将始终创建一个矢量:

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

如果您将0更改为任何非零值,它将创建一个System.Object[*],并且转换将失败。


1
@Juan:实例的创建与编译器无关 - 它是运行时/框架。Activator.CreateInstance(type) 创建一个不同类型的实例非常奇怪。 - Jon Skeet
1
谢谢@JonSkeet。我说错了,我的意思是运行时可能正在优化操作。也有可能Activator具有内部逻辑,确定您正在请求等效于向量的内容。我会尽力找到源代码并在有机会时查看。关键是,已经做出了决定,结果相当于一个向量。 - JuanR
1
@Juan:是的,那样做很有道理。不过还是有点奇怪 :) - Jon Skeet
是的,我在想是否有可能物理上创建一个一维多维数组的实例,这也引出了为什么该类型存在的问题。感觉有点像是一个技巧性的解决方法 :) - Andras Zoltan
4
大家加油啊,给Jon点个赞,让他获得100万声望值 :-) - Milosz Krajewski
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接