如何创建只读数组?

时间:2018-08-15 16:59:52

标签: arrays powershell readonly

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

谢谢

1 个答案:

答案 0 :(得分:3)

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].

请注意,该错误消息在某种程度上具有误导性,因为它仅是不允许通过索引进行 write 访问, read 访问(例如$readOnlyColl[0] )效果很好。

虽然 $readOnlyColl并不是严格意义上的数组,但它的行为就像一个  出于所有实际目的。
从技术上讲,$readOnlyColl是泛型类型System.Collections.ObjectModel.ReadOnlyCollection`1的实例,它使用从输入数组的元素推断出的元素类型 [2]
注意事项返回集合只是围绕数组的包装器 ,并且,根据您应用的特定输入数组和类型,其后的修改输入数组的元素可以反映在包装器集合中。 [3]


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

例如,根据[string]个值创建一个[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)

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


仅说明为什么Set-Variable myVar -Option ReadOnly 不足以创建只读的 array :它使 variable 只读,表示您不能为 it 分配其他值;相比之下,不会阻止修改恰好存储在变量中的数据的属性(例如数组的元素)。


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

[2]也就是说,即使PowerShell默认创建[object[]]数组,如果实际元素碰巧都是同一类型,PowerShell会选择该特定类型而不是[object] ;在当前情况下,由于输入数组的两个元素都是 strings ,因此在幕后创建了一个新的[string[]类型的数组,其结果是只读集合 wraps < / em>作为[System.Collections.ObjectModel.ReadOnlyCollection[string]]类型。

[3]因为该集合只是输入数组周围的包装器,所以任何有权访问该输入数组的人都可以修改其元素,而包装器集合将反映该更改。 br /> 但是,在 PowerShell 中,如果 PowerShell恰巧在其通过的场景后面创建了一个 new 数组,则通常会避开此潜在问题到[Array]::AsReadOnly()。假设您没有在[object[]]调用中将这样的数组显式转换为[object[]],则会为PS数组([Array]::AsReadOnly())创建一个新数组,其元素都恰好具有相同的类型。对于特定类型的输入数组(例如[int[]]),仅当您强制转换为不同类型(例如[string[]])时,才会创建新数组;创建 no 新数组时包装器问题的演示:
$arr = [int[]] (1..3); $coll = [Array]::AsReadOnly($arr); $arr[1] = 42; $coll[1] -$coll[1]现在反映了42,即通过基础数组$a分配的 changed 值。