变量更改值无需重新分配 [英] Variable changes value without re-assignment

查看:57
本文介绍了变量更改值无需重新分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个变量,它通过我更新不同变量的值来改变它的值.

我正在尝试创建自己的对象,并尝试使用我在网上找到的一些代码,但我偶然发现了这个问题,无法理解这是如何发生的.

准备工作:

$a = "" |select First,Last #This 只是创建一个具有两列的自定义对象.$b = @() #这只是一个空数组,稍后用'$A'的值填充$a.first = "阿尔法"$a.last = "Bravo"$b += $a$a.first = "查理"$a.last = "三角洲"$b += $a

应该发生什么:

<前>首尾----- ----阿尔法布拉沃查理三角洲

但实际结果是:

<前>首尾----- ----查理三角洲查理三角洲

这里出了什么问题?

解决方案

正如 Lee_Dailey 指出的那样,你'将 references 添加到存储在 $a 中的自定义对象 ([pscustomobject][1]) 实例到数组$b(假设 [pscustomobject]引用类型),并且您正在更新相同的自定义对象,因此您最终与:

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

最直接的解决方法是在分配新的属性值之前创建 $acopy,这可以通过 .psobject.Copy(),它创建了一个 - 浅 - 克隆:

<代码>...# 创建 $a 的副本以创建下一个数组元素.$a = $a.psobject.Copy()$a.first = "查理"$a.last = "三角洲"$b += $a

当然,您可以避免这个问题并使用自定义对象文字(PSv3+)代替,它每次都会创建一个新实例:

$b = @()$b += [pscustomobject] @{第一个 = "阿尔法"last = "Bravo"}$b += [pscustomobject] @{第一个 = "查理"最后=德尔塔"}

顺便说一句:使用 += 增长数组效率低下,因为每次都必须在幕后创建一个新数组;这可能不会在只有少数添加/迭代时引起注意,但如果数量较多,最好使用列表数据类型,例如 [System.Collections.Generic.List[object]]::>

$b = 新对象 System.Collections.Generic.List[object]$b.Add([pscustomobject] @{第一个 = "阿尔法"last = "Bravo"})$b.Add([pscustomobject] @{第一个 = "查理"最后=德尔塔"})

<小时>

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

[pscustomobject](实际上与 [psobject] 相同)是 PowerShell 的属性包"类型,它允许您ad hoc 不需要提前声明不同的 .NET 类型;从 .NET 的角度来看,给定的自定义对象的类型始终是 System.Management.Automation.PSCustomObject,但具体的动态附加属性可能因设计而异.

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

PS>("" | 选择第一个,最后一个).pstypenamesSelected.System.String #自定义类型名称以反映*input*的类型System.Management.Automation.PSCustomObject # 真正的类型名称System.Object # 基类型的名称

上述创建自定义对象的方法已过时,但是,PSv3+ 支持直接构造的文字 [pscustomobject] @{ ... } 语法,它具有添加了能够将属性作为同一语句的一部分初始化并且比Select-Object(以及New-对象):

# PSv3+ 相当于上面的#(自定义的Selected.System.String"类型名称除外),# 允许你也初始化属性.[pscustomobject] @{第一个 = $null最后= $null}

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

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

I have a variable that changes it's values by me updating the values from a different variable.

I'm trying to create my own object and was experimenting with some code I found online and I stumbled on this issue and can't wrap my head on how this happens.

Preparations:

$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

What is supposed to happen:

First   Last
-----   ----
Alpha   Bravo
Charlie Delta

But the actual results are:

First   Last
-----   ----
Charlie Delta
Charlie Delta

What is wrong here?

解决方案

As Lee_Dailey points out, you're adding references to the custom object ([pscustomobject][1]) instance stored in $a to array $b (given that [pscustomobject] is a reference type), and you're updating the same custom object, so that you ended up with:

  • 2 array elements that point to the very same object...
  • ... whose property values are the last ones you assigned.

The most immediate fix is to create a copy of $a before assigning new property values, which can be done with .psobject.Copy(), which creates a - shallow - clone:

...
# Create a copy of $a to create the next array element.
$a = $a.psobject.Copy()

$a.first = "Charlie"
$a.last = "Delta"
$b += $a

Of course, you could avoid the problem and use custom-object literals (PSv3+) instead, which creates a new instance every time:

$b = @()

$b += [pscustomobject] @{ 
  first = "Alpha"
  last = "Bravo"
}

$b += [pscustomobject] @{ 
  first = "Charlie"
  last = "Delta"
}

As an aside: growing arrays with += is inefficient, because a new array must be created behind the scenes every time; this may not be noticeable with only a few additions / iterations, but with a larger number it's better to use a list data type such as [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] Custom objects in PowerShell:

[pscustomobject] (which is effectively the same as [psobject]) is PowerShell's "property bag" type that allows you to construct objects ad hoc without requiring a distinct .NET type declared ahead of time; from the perspective of .NET, a given custom object's type is always System.Management.Automation.PSCustomObject, though the specific, dynamically attached properties can differ, by design.

Select-Object (select) too outputs [pscustomobject] instances, though they report a custom type name, via PowerShell's ETS (Extended Type System), as their primary type name:

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

The above method of creating custom objects is obsolete, however, and PSv3+ supports literal [pscustomobject] @{ ... } syntax for direct construction, which has the added advantages of being able to initialize the properties as part of the same statement and being faster than Select-Object (and also 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 
}

Note: In PSv2 you could use New-Object PSCustomObject -Property @{ ... } to similar effect, but the order in which the properties are attached will typically not reflect the definition order.

Note that you can always instantiate regular .NET types in PowerShell as well, with the New-Object cmdlet or, in PSv5+, alternatively with syntax [<type>]::new([...]). You use the same methods to instantiate PSv5+ custom classes declared with the class keyword.

这篇关于变量更改值无需重新分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆