Powershell foreach-Loop:无法设置数组项

时间:2016-12-02 12:42:21

标签: arrays powershell foreach pass-by-reference pass-by-value

我现在完全迷失在心灵循环中:

我想解决通过值而不是引用将数组传递给函数的问题,并找到了这个解决方案: Is Arraylist passed to functions by reference in PowerShell

.Clone() - 方法按预期工作:

function testlocal {
   param ([collections.arraylist]$local)
   $local = $local.Clone()
   $local[0] = 10

   return $local
 }

 $local = [collections.arraylist](1,2,3)

 'Testing function arraylist'    
 $copyOfLocal = testlocal $local
 $copyOfLocal

 'Testing local arraylist'
 $local

输出:

Testing function arraylist
10
2
3

Testing local arraylist
1
2
3

但是现在我需要在foreach循环中处理数组的元素。然后会发生的是,数组不会被foreach循环(???)修改。尽管进行了大量研究,但我仍然无法理解这一点。你能否向我解释幕后发生的事情以及如何避免这种情况? 我需要在函数的foreach循环中修改原始数组的副本。在我的真实脚本中,数组由自定义PSObject组成,但行为是相同的。

function testlocal {
   param ([collections.arraylist]$local)
   $local = $local.Clone()
   $local[0] = 10

   foreach ($item in $local) {
      $item = 100
   }

   return $local
 }

 $local = [collections.arraylist](1,2,3)

 'Testing function arraylist'    
 $copyOfLocal = testlocal $local
 $copyOfLocal

 'Testing local arraylist'
 $local

foreach循环不会改变输出:

Testing function arraylist
10
2
3

Testing local arraylist
1
2
3

更新2016-12-14 带有for循环的提示有效,但是当使用对象时,整个克隆事情再次崩溃:

 function testlocal {
   param ([collections.arraylist]$local)
   $local = $local.Clone()

 for($i = 0; $i -lt $local.Count; $i++){ 

   $local[$i].Hostname = "newname" 
   }
   return $local

 }

$target1 = New-Object -TypeName PSObject
$target1 | Add-Member -MemberType NoteProperty -Name "Hostname" -Value "host1"

$target2 = New-Object -TypeName PSObject
$target2 | Add-Member -MemberType NoteProperty -Name "Hostname" -Value "host2"


 $local = [collections.arraylist]($target1,$target2)

 'Testing function arraylist'    
 $copyOfLocal = testlocal $local
 $copyOfLocal | ft

 'Testing local arraylist'
 $local | ft

输出:

Testing function arraylist

Hostname
--------
newname 
newname 

Testing local arraylist

Hostname
--------
newname 
newname 

突然间,我又回到了参考路线。这让我很生气! 请帮忙!

1 个答案:

答案 0 :(得分:0)

当您通过调用foreach枚举数组时,您将获得内容的副本,并且任何更改都将被丢弃。正如Mathias Jessen所提到的,你可以使用for循环来改变arraylist。

编辑2016-12-16 好吧,我调查了它,arraylist克隆方法不像你那样工作,我认为它确实如此。根据{{​​3}},它返回一个浅拷贝,即它“只复制集合的元素,无论它们是引用类型还是值类型,但它不复制引用引用的对象”。你和我都认为克隆会产生所谓的“深拷贝”。

在使用基本数据类型Int32的原始示例中,深层和浅层副本是相同的,而在使用PSObjects的更新示例中,它们不是,并且仅复制了引用。可以在此MSDN中找到深度克隆对象的方法。

我没有找到关于此的文档,但似乎foreach也会做浅文本:

$object1 = New-Object -TypeName PSObject -Property @{Hostname="host1"}
$object2 = New-Object -TypeName PSObject -Property @{Hostname="host2"}
$array_of_objects = [collections.arraylist]($object1,$object2)

# Looping through basic values, call by value
foreach ($string in $array_of_objects.Hostname)
{
    $string = "newname"
}
$array_of_objects.Hostname

# Looping through objects, call by reference
foreach ($object in $array_of_objects)
{
    $object.Hostname = "newname"
}
$array_of_objects.Hostname

希望这有帮助。