0

Ich bin in einem Geist Schleife im Moment völlig verloren:Powershell foreach-Schleife: nicht Array-Elemente gesetzt

ich das Problem der Übergabe eines Arrays an eine Funktion von Wert anstelle von Referenz- und fanden diese lösen wollte Lösung: Is Arraylist passed to functions by reference in PowerShell.

Die .Clone() - Methode funktioniert wie erwartet:

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 

Ausgang:

Testing function arraylist 
10 
2 
3 

Testing local arraylist 
1 
2 
3 

Aber jetzt brauche ich die Array-Elemente in einer foreach-Schleife zu verarbeiten. Was dann passiert ist, dass das Array nicht durch die foreach-Schleife (???) modifiziert wird. Das verstehe ich trotz vieler Nachforschungen nicht. Könntest du mir bitte erklären, was hinter den Kulissen passiert und wie ich das vermeiden kann? Ich muss eine Kopie des ursprünglichen Arrays innerhalb einer foreach-Schleife einer Funktion ändern. In meinem echten Skript besteht das Array aus benutzerdefinierten PSObjects, aber das Verhalten ist das gleiche.

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 

Ausgabe wird nicht durch die foreach-Schleife geändert:

Testing function arraylist 
10 
2 
3 

Testing local arraylist 
1 
2 
3 

UPDATE 2016.12.14 Die Spitze mit der for-Schleife funktioniert, aber es stellt sich heraus, wenn Objekte verwenden, die ganze Klonen-Sache fällt wieder auseinander:

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 

Ausgang:

Testing function arraylist 

Hostname 
-------- 
newname 
newname 

Testing local arraylist 

Hostname 
-------- 
newname 
newname 

Plötzlich bin ich wieder durch Referenz wieder vorbei. Das macht mich verrückt! Bitte helfen!

+1

Verwenden Sie eine for-Schleife: 'für ($ i = 0; $ i -lt $ local.Count; $ i ++) {$ local [$ i] = 100}' –

+0

Danke, aber das scheint nicht zu funktionieren Objekte, siehe mein Update am Ende meines ursprünglichen Posts. Irgendeine andere Idee, wie man damit umgeht? – Damartala

Antwort

0

Wenn Sie das Array durch Aufrufen von foreach aufzählen, erhalten Sie Kopien des Inhalts und alle Änderungen werden verworfen. Wie Mathias Jessen bereits erwähnt hat, können Sie eine For-Schleife verwenden, um Änderungen an der Arraylist vorzunehmen.

BEARBEITEN 2016-12-16 Okay, ich habe es untersucht und die Arraylist Klon-Methode funktioniert nicht wie du und ich dachte, es tut. Gemäß MSDN wird eine flache Kopie zurückgegeben, d. H. Es "kopiert nur die Elemente der Sammlung, ob es sich um Referenztypen oder Werttypen handelt, kopiert jedoch nicht die Objekte, auf die sich die Referenzen beziehen". Du und ich, wo beide annehmen, dass der Klon eine so genannte "tiefe Kopie" erzeugen würde.

In Ihrem ursprünglichen Beispiel, das den grundlegenden Datentyp Int32 verwendet, sind tiefe und oberflächliche Kopien die gleichen, während sie in Ihrem aktualisierten Beispiel mit PSObjects nicht und nur die Referenzen kopiert werden. Eine Methode zum Tiefenklonen von Objekten finden Sie in dieser thread.

Ich habe keine Dokumentation zu diesem Thema finden, aber es scheint, als ob foreach auch flache Kopien tun würde:

$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 

Hoffnung, das hilft.

+0

Hallo, danke für deine schnellen Antworten, @Mathias R. Jessen und josges.Entschuldigung, aber ich konnte dem nicht früher folgen. Die For-Schleife funktioniert wie erwartet, aber nicht wenn ich Objekte verwende ?? Ich habe dieses Problem meinem ursprünglichen Beitrag hinzugefügt, weil ich es nicht in einen Kommentar einfügen konnte. Hast du auch eine Ahnung davon? Vielen Dank! – Damartala

Verwandte Themen