您将如何调用C#中数组引入的多态性

本文关键字:数组 多态性 何调用 调用 | 更新日期: 2023-09-27 18:00:18

AFAIK在基础结构(CLI/.Net/Mono)级别有一种类型来表示阵列:System.Array

从物理上讲,这是一个线性的值序列,但从逻辑上讲,它们可以被认为是在不止一个维度上组织的。

在语言级别(例如C#),这种逻辑视图得益于一些语法糖:

2D: T[,]
3D: T[,,]
42D: T[,,,...,,,]

有一个明显的参数多态性,例如在1D数组后面可以隐藏多种类型的数组:

Array of integers: int[]
Array of strings references: string[]
Array of objects references: object[]

但是,您如何描述结构多态性,即数组可以有多个维度?

在基础设施级别,这不再是类型系统的一部分,只是一个逻辑视图,所以我认为根本不存在多态性。

但在语言级别,它可能被认为是某种包含多态性,因为所有数组在逻辑上都是从公共基类继承的不同类型。

欢迎任何意见和更正。

您将如何调用C#中数组引入的多态性

System.Array类有一个本质上无限的导数族,每个元素类型和可能的维数都有一个导数族。因为数组早于泛型,所以它们有一种特殊的"准硬编码"方法来实现这一点。基本上,.NET Framework包含一个特殊的硬编码"配方",因此给定一个基项类型和多个维度,它可以生成一个从System.Array派生的类型,该类型将充当具有指定的基项类型与维度的数组。此外,由于数组协方差的工作方式,数组可以表现得好像它们实现的接口实际上不是其类的一部分,这是其他类型所不能做到的。例如,因为类型Cat[]的引用也是类型Animal[]的引用,所以Cat[]不仅实现IList<Cat>,还实现IList<Animal>

不存在除System.Array之外的任何类型都可以支持这种协方差的机制,也不存在用户代码可以定义类族的任何方式,使得对于任何整数n,都将存在其get方法采用n参数的导数。.NET中的泛型类型可以做很多数组不能做的事情,但由于数组是通过泛型类型功能之外的机制实现的,因此它们可以支持一些功能无法实现的功能。

所有派生数组类型都是从System.Array派生的,并覆盖适当的方法。不过,数组有点特别,因为CLR中以IL操作码的形式提供了烘焙支持,这些操作码直接与具体的数组类型交互。尽管如此,这与其他类的基类多态性是相同的,至少在通过Array类访问时是这样。

然而,数组实际上并不是你所想的维度上的"多态"。一个特定的数组实例在构造时被分配了一个特定维度,并且它只能与该维度一起使用。这在操作代码级别和GetValue方法中都会发生。"Item"(索引器)的IList实现也仅支持单个维度;如果您尝试在多维数组中使用它,您将得到一个ArgumentException。


此外,为了防止不清楚,A[x,y]语法实际上并不是语法糖。多维数组实际上被排除在内置CLR支持之外,而是通过方法访问。这编译成类似以下IL:的内容

Ldloc A //(load array A onto the operation stack)
Ldloc x //(load value of variable x onto the operation stack)
Ldloc y //(load value of variable y onto the operation stack)
call int32[,]::Get(int, int) //(return a 4-byte signed integer from the array at indices [x,y], putting the result onto the operation stack)

您可以将其与一维阵列A[x]:的相同情况进行比较

Ldloc A //(load array A onto the operation stack)
Ldloc x //(load value of variable x onto the operation stack)
Ldelem_I4 //(return the 4-byte signed integer from the array at index [x] and put the result onto the operation stack)

但是你如何描述结构多态性,数组可以有多个维度?

三点:

  • 在语言级别上,多维数组符合内部多态性的条件
  • 由于多维数组可以用关联数组或列表来模拟,因此它不需要依赖于特定的数据结构
  • 由于多维数组可以在运行时创建,因此不需要依赖于类型检查

参考

  • 在运行时创建二维数组
  • OO优步狂热被认为是愚蠢的
  • c++是如何在内部实现多态性的
  • 重构Switch语句
  • C2维基:外部多态性