可变变化值而无需重新分配



我有一个变量,可以通过我从其他变量更新值来更改其值。

我正在尝试创建自己的对象,并正在尝试在网上找到的一些代码,但我偶然发现了这个问题,无法将我的头缠住。

准备:

$a = "" | select First,Last #This just creates a custom object with two columns.
$b = @() #This is just an empty array to fill later on with the values of '$A'
$a.first = "Alpha"
$a.last = "Bravo"
$b += $a
$a.first = "Charlie"
$a.last = "Delta"
$b += $a

应该发生的事情:

第一个------ ------Alpha Bravo查理三角洲

,但实际结果是:

第一个------ ------查理三角洲查理三角洲

这里有什么问题?

正如Lee_dailey指出的那样,您将参考添加到自定义对象([pscustomobject] [1] (实例中存储在$a中数组$b(鉴于[pscustomobject]是A 参考类型(,并且您正在更新相同的自定义对象,因此您最终出现了:

  • 2个数组元素指向同一对象...
  • ...其属性值是您分配的最后一个值。

最直接的修复是在分配新属性值之前创建$a的A copy ,可以用.psobject.Copy()来完成,该值可以创建一个 - 浅 - 克隆:

...
# Create a copy of $a to create the next array element.
$a = $a.psobject.Copy()
$a.first = "Charlie"
$a.last = "Delta"
$b += $a

当然,您可以避免问题并使用custom-object 文字(psv3 (,这每次都会创建一个新实例:

$b = @()
$b += [pscustomobject] @{ 
  first = "Alpha"
  last = "Bravo"
}
$b += [pscustomobject] @{ 
  first = "Charlie"
  last = "Delta"
}

顺便说一句:使用+=的生长数组效率低下,因为每次都必须在幕后创建一个新数组;这可能仅使用几个添加/迭代可能不明显,但是使用较大的数字,最好使用列表数据类型,例如[System.Collections.Generic.List[object]]

$b = New-Object System.Collections.Generic.List[object]
$b.Add([pscustomobject] @{ 
  first = "Alpha"
  last = "Bravo"
})
$b.Add([pscustomobject] @{ 
  first = "Charlie"
  last = "Delta"
})

[1] PowerShell中的自定义对象:

[pscustomobject](实际上与[psobject]相同(是PowerShell的"属性袋"类型,它允许您构建对象 adhoc 而无需提前声明的不同的.NET类型;从.NET的角度来看,给定的自定义对象的类型始终是System.Management.Automation.PSCustomObject,尽管特定的,动态附加的属性可以通过设计而有所不同。

Select-Object(select(也输出[pscustomobject]实例,尽管它们通过PowerShell的ETS(扩展类型系统(报告了自定义类型名称,作为其主要类型名称:

PS> ("" | select First,Last).pstypenames
Selected.System.String  # custom type name to reflect the type of the *input*
System.Management.Automation.PSCustomObject # the true type name
System.Object # the name of the base type

创建自定义对象的上述方法是过时的,但是PSV3 支持直接构造的字面 [pscustomobject] @{ ... }语法,这具有能够初始化的附加优势。属性作为同一语句的一部分,并且比Select-Object快(以及New-Object(:

# PSv3+ equivalent of the above 
# (except for the custom 'Selected.System.String' type name),
# allowing you to also initialize the properties.
[pscustomobject] @{
   First = $null  
   Last = $null 
}

注意:在PSV2中,您可以使用New-Object PSCustomObject -Property @{ ... }来相似效果,但是附加属性的顺序通常不会反映定义顺序。

请注意,您始终可以使用New-Object cmdlet或在PSV5 中实例化PowerShell的常规.NET类型,或者使用语法[<type>]::new([...])进行实例化。您使用相同的方法来实例化PSV5 用class关键字声明的自定义类。

最新更新