如何创建只读数组?

How to create Readonly array?

我有一些使用 Set-Variable myVar -Value 10 -Option ReadOnly 语法设置的只读变量,但我也需要只读数组。如何制作只读数组?

谢谢

PetSerAl,像以前无数次一样,在对问题的简短评论中提供了解决方案;他还帮助改进了这个答案:
使用[Array]::AsReadOnly($someArray),在PSv3+[1]中可用 :

# Create a 2-element read-only collection containing strings.
$readOnlyColl = [Array]::AsReadOnly(('one', 'two'))

# Try to modify an element, which now fails:
$readOnlyColl[0] = 'uno'

PSv2 中,使用转换为 [System.Collections.ObjectModel.ReadOnlyCollection[<type>]],如下所示。

上面的结果如下,表明元素不能被修改:

Unable to index into an object of type System.Collections.ObjectModel.ReadOnlyCollection`1[System.String].

请注意,该错误消息有些误导,因为它只是不允许通过索引进行 写入 访问,读取 访问(例如,$readOnlyColl[0])工作得很好。

虽然 $readOnlyColl 不是严格意义上的 数组 ,但它的行为类似于 出于所有实际目的。
从技术上讲,$readOnlyColl 是泛型类型 System.Collections.ObjectModel.ReadOnlyCollection`1 的实例,它使用从输入数组的元素 .[2][=114 推断出的 元素类型=]
警告return 集合只是数组 周围的包装器,并且取决于您应用的特定输入数组和强制转换,以后对输入数组元素的修改可以反映在包装器集合中。[3]


如果你想显式控制元素的数据类型,使用cast .

例如,从 [int] 个值创建一个 [string] 类型的集合:

# Cast to an array of the desired type first.
[Array]::AsReadOnly([string[]] (1, 2, 3)

# Alternatively, cast to the target collection type directly.
# Always use this in PSv2, where [Array]::AsReadOnly() cannot be called.
[System.Collections.ObjectModel.ReadOnlyCollection[string]] (1, 2, 3)

[object] 类型的元素使用 [object[]] / [object],与常规 PowerShell 数组一样,但请注意,如果输入数组确实已经是 [object[]] 数组,生成的集合将是数组周围的 wrapper - 参见脚注 [2].


只是为了说明 为什么 Set-Variable myVar -Option ReadOnly 不足以 创建一个只读的 数组 :它使变量只读,这意味着你不能给赋不同的值;相比之下,修改碰巧存储在变量中的数据 的 属性 - 例如数组的元素 - 不会被阻止。


[1] 该方法从.NET v2 开始可用,PSv2 构建于其上;但是,只有 PSv3 引入了直接调用 generic 方法的能力,因此需要 PSv3+;但是,在 PSv2 中,您可以直接转换为 [System.Collections.ObjectModel.ReadOnlyCollection[<type>]]

[2] 也就是说,即使 PowerShell 默认创建 [object[]] 数组,如果实际元素碰巧都是同一类型,PowerShell 会选择该特定类型而不是 [object];在手头的例子中,因为输入数组的两个元素都是 strings,所以在幕后创建了一个新的 [string[] 类型数组,由此产生的只读集合 wraps 类型 [System.Collections.ObjectModel.ReadOnlyCollection[string]].

[3] 因为集合只是输入数组周围的 包装器 ,任何有权访问输入数组的人仍然可以修改它的元素和包装器集合将反映这种变化。
然而,在 PowerShell 中,您通常可以避免这个潜在问题 if PowerShell 碰巧创建了一个 new 数组,然后传递给 [Array]::AsReadOnly()。为 PS 个数组 ([object[]]) 创建一个新数组,其元素恰好具有相同的类型,假设您没有在 [=31] 中显式地将这样的数组转换为 [object[]] =] 打电话。对于特定类型的输入数组(例如 [int[]]),仅当您转换为 不同的 类型(例如 [string[]])时才会创建新数组;如果创建 no 新数组,则包装器问题的演示:
$arr = [int[]] (1..3); $coll = [Array]::AsReadOnly($arr); $arr[1] = 42; $coll[1] - $coll[1] 现在反映了 42,即通过底层数组 $a.
[= 分配的 changed 值43=]