从技术上讲,有两种类型的数组。矢量类型或矩阵类型。运行时将 Vector 类型称为Sz_Array
,它们是您在声明一维数组*时获得的类型。我不知道为什么。矩阵类型表示多维数组。不幸的是,它们都继承自Array
其他中间类型,但没有其他中间类型。
为什么 Array 类不直接公开其索引器?
当您将其作为 a 时,您只能访问一维数组的索引器的原因T[]
是因为一维数组的索引器是通过 IL 操作码在运行时实现的。
例如
static T GetFirst<T>(T[] a)
{
return a[0]:
}
转换为以下 il::
L_0000: ldarg.0
L_0001: ldc.i4.0
L_0002: ldelem.any !!T
L_0007: ret
如下 C#
private static T GetFirst<T>(IList<T> a)
{
return a[0];
}
转换为这个 IL。
L_0000: ldarg.0
L_0001: ldc.i4.0
L_0002: callvirt instance !0 [mscorlib]System.Collections.Generic.IList`1<!!T>::get_Item(int32)
L_0007: ret
所以我们可以看到一个是使用操作码ldelem.any
,另一个是callvirt
方法。
运行时在运行时为数组注入IList<T>,IEnumerable<T>
。MSIL 中它们的逻辑位于类中SZArrayHelper
提供实现的运行时还为生成的每个数组创建两个辅助方法,以帮助不支持索引器的语言(如果存在这种语言)C# 不会公开它们,但它们是可以调用的有效方法。他们是:
T Get(Int32)
void Set(Int32, T)
这些方法也会根据维度为矩阵类型数组生成,并在调用索引器时由 C# 使用。
但是,除非您实际指定您是类型化数组,否则您不会获得索引器。由于 Array 没有索引器方法。不能使用操作码,因为在编译时您需要知道所讨论的数组是向量类型和数组的元素类型。
但是 Array 实现了 IList!那有一个索引器我不能叫它吗?
是的,但是 IList 方法的实现是显式实现,因此它们只能在 C# 中在强制转换或受泛型约束绑定时调用。可能是因为对于任何非向量类型的数组,当您调用其任何方法时,它都会引发不受支持的异常。由于它唯一有条件地支持运行时的创建者,因此当您知道这是一个一维数组时,可能希望您将其强制转换,但我现在无法命名该类型。
IList
如果不支持任何多维数组的实现抛出,为什么数组实现?
这可能是自 1.0 以来就存在的错误。他们现在无法修复它,因为无论出于何种原因,他们都可能将多维数组转换为IList
. 在 2.0 中,他们添加了一些运行时魔法,以便在运行时向向量类型类添加实现,以便只有一维数组实现IList<T>
和IEnumerable<T>
.
我们可以插入您的下一个问题::
如何在不强制转换的情况下让索引器出现?将方法签名更改为::
public static T[] ToArray<T>(this T source)
但是你可能会说你的 ToArray 没有返回 T[],它返回了别的东西我该怎么办?如果您可以明确指定返回类型,请执行此操作。如果它是一种引用类型,您总是可以滥用数组协方差并将返回类型更改为,object[]
但是您将受到 ArrayTypeMismatchException 的摆布。如果您要返回一个值类型,这将不起作用,因为该强制转换是非法的。此时您可以直接返回IList
,但随后您将元素装箱并且您仍然受 ArrayTypeMismatchException 的摆布。Array 是所有数组类型的基类,因为它有帮助方法来帮助您访问内容,例如GetValue
和SetValue
您会注意到它们具有采用索引数组的重载,以便您可以访问 Nd 和 1d 数组中的元素。例如
IList myArray = ToArray(myValues);
// myArray is actually a string array.
myArray[0]='a';
// blows up here as you can't explicitly cast a char to a string.
所以短处是你不知道显式类型。Array
并且implementation的每个继承者IList
,即使它没有多大意义,也是一个他们无法更改的实现细节,因为它自 1.0 以来就在那里。
- 从技术上讲,这不是 100% 正确的。您可以创建一个只有一维的矩阵类型数组。这个可怕的憎恶可以在 IL 中创建,或者您可以使用
typeof(int).MakeArrayType(1)
通知您现在如何拥有System.Int32[*]
而不是创建类型System.Int32[]