【问题标题】:How would you call the kind of polymorphism introduced by arrays in C#您如何称呼 C# 中数组引入的那种多态性
【发布时间】:2014-06-12 21:24:51
【问题描述】:

在基础架构 (CLI/.Net/Mono) 级别的 AFAIK 有一种表示数组的类型:System.Array

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

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

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

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

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

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

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

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

欢迎任何输入和更正。

【问题讨论】:

  • 我不知道程序员可以使用它的任何情况,所以我根本不会称之为多态性;您的 42D 数组永远不会在程序中采用另一种数组形式,因为数组可以被视为类 Object
  • @JohnC: AFAIK 你可以有一个方法来接受System.Array 并根据它的维度转储它的值。这显然是多态性。并且可能是某种包含多态性。
  • 数组类型也存在于 CLR 级别。不仅仅是在 C# 级别。但是,这两种类型系统并不完全一致。数组维度不仅仅是一个逻辑概念。您不能将数组转换为不同的维度。尺寸存储在对象中并且是固定的。

标签: c# .net arrays oop polymorphism


【解决方案1】:

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

除了System.Array 之外的任何类型都没有任何机制可以支持这种协方差,也没有任何方法可以让用户代码定义一个类族,这样对于任何整数n 都会有一个其导数get 方法采用 n 参数。 .NET 中的泛型类型可以做许多数组不能做的事情,但是由于数组是通过泛型类型工具以外的机制实现的,它们可以支持一些工具无法实现的功能。

【讨论】:

  • 所以在 .Net 级别我们有一些动态包含多态性:子类型是动态生成的?
  • @Pragmateek:我不知道确切的细节,它们可能在 .NET 版本之间有所不同,但数组、委托、字符串、可空对象和结构在运行时都有一些特殊的“魔力”这允许他们做其他类型不能做的事情。一些“魔法”可能已经暴露给用户类型,从而消除了类型本身具有神奇行为的需要(例如,系统可以允许标记结构以指示它们是否应该满足struct 约束,并且在ValueType 中将装箱和拆箱指令链接到虚拟方法,其...
  • ...默认实现等同于当前的装箱/拆箱指令。这不仅允许将int 拆箱到int?,而且还可以拆箱long [如果long 的拆箱方法包括为此提供的规定])。当然,如果从一开始就包含泛型,.NET 的许多方面可能看起来会大不相同,但它也有可能永远不会起步。
【解决方案2】:

所有派生数组类型都从System.Array 继承并覆盖相应的方法。不过,数组有点特殊,因为 CLRIL 操作码 的形式提供了直接与具体数组类型交互的内置支持。尽管如此,这仍然是与其他类相同的基类多态性,至少在通过 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)

【讨论】:

  • 我不认为接口IList有任何实现。
【解决方案3】:

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

三点:

  • 在语言级别,多维数组可以称为内部多态
  • 由于可以使用关联数组或列表来模拟多维数组,因此无需依赖特定的数据结构
  • 由于可以在运行时创建多维数组,因此无需依赖类型检查

参考文献

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-19
    • 1970-01-01
    • 2018-11-29
    • 2019-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多