首页 > 解决方案 > 如何创建只读数组?

问题描述

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

谢谢

标签: arrayspowershellreadonly

解决方案


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的泛型类型的实例。[2]警告返回集合只是数组的包装器,并且根据您应用的特定输入数组和强制转换,以后对输入数组元素的修改可能会反映在包装器集合中。[3]System.Collections.ObjectModel.ReadOnlyCollection`1


如果要显式控制元素的数据类型,请使用强制转换

例如,从值创建一个[string]-typed 集合[int]

# 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)

与常规 PowerShell 数组一样,将[object[]]/[object]用于[object]类型元素,但请注意,如果输入数组确实已经是[object[]]数组,则生成的集合将是数组的包装器- 请参见脚注 [2]。


仅说明为什么创建只读数组Set-Variable myVar -Option ReadOnly不够的:它使变量只读,这意味着您不能为其分配不同的;相比之下,修改碰巧存储在变量中的数据的属性——例如数组的元素——是不会被阻止的。


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

[2] 也就是说,即使 PowerShell[object[]]默认创建数组,如果实际元素恰好都是相同类型,PowerShell 会选择该特定类型而不是[object]; 在本例中,因为输入数组的两个元素都是字符串,所以在幕后创建了一个新的[string[]类型化数组,生成的只读集合将其包装为 type [System.Collections.ObjectModel.ReadOnlyCollection[string]]

[3] 因为集合只是输入数组的一个包装器,任何可以访问输入数组的人仍然可以修改它的元素,并且包装器集合会反映这种变化。
但是,在PowerShell中,如果PowerShell 碰巧在幕后创建了一个[Array]::AsReadOnly()数组,然后将其传递给. 为 PS 数组 ( [object[]]) 创建一个新数组,其元素恰好具有相同的类型,假设您没有[object[]][Array]::AsReadOnly()调用中显式转换这样的数组。对于特定类型的输入数组[int[]]例如,[string[]]); 如果没有创建新数组,则演示包装器问题:
$arr = [int[]] (1..3); $coll = [Array]::AsReadOnly($arr); $arr[1] = 42; $coll[1] -$coll[1]现在反映42,即通过基础数组分配的更改值,$a


推荐阅读