致complement Mathias R. Jessen's helpful answer:
您对[ref] 的使用毫无意义,因为仅$Pointer = $Tree.Children 就足以将引用复制到存储在$Tree.Children 中的数组中。
关于[ref]的适当使用的讨论见底部。
因此,both $Tree.Children 和 $Pointer 将包含对同一数组的引用,就像 $Pointer.Value 在基于 [ref] 的方法中所做的那样。
因为+= 创建了一个新 数组,但是,无论LHS 上的什么——无论是$Pointer.Value 还是没有[ref],只有$Pointer——只接收一个 new 引用 new 数组,而 $Tree.Children 仍然指向旧数组。
您可以通过使用直接确定两个变量或表达式是否“指向”引用类型(所有集合都是)的同一实例来验证这一点:
PS> [object]::ReferenceEquals($Pointer.Value, $Tree.Children)
False
注意[object]::ReferenceEquals() 仅适用于reference types,不适用于value types - 包含后者的变量直接 存储值而不是引用 存储的数据其他地方。
Mathias 的方法通过使用 [List`1] 实例而不是数组来解决您的问题,数组可以通过其 .Add() 方法就地扩展,以便将引用存储在 $Pointer[.Value]永远不需要更改并继续引用与 $Tree.Children 相同的列表。
关于您的后续问题:[ref] 的适当使用:
$Tree2 = @()
$Pointer = [ref] $Tree2
在这种情况下,因为[ref] 应用于变量 - 按照设计 - 它创建了一个有效的变量别名:@987654351 @ 保持指向 $Tree2 包含的任何内容,即使稍后将不同的数据分配给 $Tree2(无论该数据是值类型还是引用类型实例):
PS> $Tree2 = 'Now I am a string.'; $Pointer.Value
Now I am a string.
还要注意更典型的[ref] 用例是将变量作为通过引用参数传递给函数。
PS> function foo { param([ref] $vRef) ++$vRef.Value }; $v=1; foo ([ref] $v); $v
2 # value of $v was incremented via $vRef.Value
相比之下,您不能使用[ref] 来创建对数据 的持久间接引用,例如属性 对象包含 在一个变量中,并且使用[ref] 基本上没有意义:
$Tree2 = @{ prop = 'initial val' }
$Pointer = [ref] $Tree2.prop # [ref] is pointless here
后来更改$Tree2.prop不会反映在$Pointer.Value中,因为$Pointer.Value静态指的是原来存储在@中的引用987654363@:
PS> $Tree2.prop = 'later val'; $Pointer.Value
initial val # $Pointer.Value still points to the *original* data
PowerShell 应该防止将[ref] 用于任何非变量。然而,[ref] 有一个合法的——尽管是异国情调的——“标签外”使用,用于促进在调用者的范围内更新值从后代范围,如概念性about_Ref 帮助主题中所示.