2016-12-02 10 views
0

我的脑海循环此刻完全丧失:PowerShell的的foreach循环:不能设置数组项

我想解决的价值,而不是引用传递数组给函数的问题,发现了这个解决方案: 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循环中修改原始数组的副本。在我的真实脚本中,数组由自定义PSObjects组成,但行为相同。

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 

UPDATE二〇一六年十二月一十四日 与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

使用for循环:'for($ i = 0; $ i -lt $ local.Count; $ i ++){$ local [$ i] = 100}' –

+0

谢谢,但这似乎不适用于对象,请参阅我的原始文章底部的更新。任何其他想法如何处理? – Damartala

回答

0

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

编辑2016-12-16 好吧,我看着它,阵列列表克隆方法不像你,我认为它的确如此。根据MSDN,它返回一个浅拷贝,即它“仅拷贝集合的元素,无论它们是引用类型还是值类型,但不拷贝引用引用的对象”。你和我都假设克隆会产生所谓的“深层复制”。

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

我没有找到这个文件,但它好像的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 

希望这有助于。

+0

嗨,感谢您的快速回复,@Mathias R. Jessen和josges。对不起,但我无法提前跟进。 for-loop按预期工作,但如果我使用的是对象,则不会我已将此问题添加到原始文章中,因为我无法将其纳入评论。你也有这个想法吗?谢谢! – Damartala