0

I'm completely lost in a mind loop at the moment:

I wanted to solve the problem of passing an array to a function by value instead of reference and found this solution: Is Arraylist passed to functions by reference in PowerShell.

The .Clone()-method works as expected:

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

Output:

Testing function arraylist
10
2
3

Testing local arraylist
1
2
3

But now I need to process the array's elements in a foreach-loop. What happens then is that the array does not get modified by the foreach-loop (???). I am at a loss to understand this, despite a lot of research. Could you please explain to me what is happening behind the scenes and how I can avoid this? I need to modify a copy of the original array within a function's foreach-loop. In my real script, the array consists of custom PSObjects, but the behavior is the same.

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

Output is not changed by the foreach-loop:

Testing function arraylist
10
2
3

Testing local arraylist
1
2
3

UPDATE 2016-12-14 The tip with the for-loop works, but it turns out when using objects, the whole cloning-thing falls apart again:

 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

Output:

Testing function arraylist

Hostname
--------
newname 
newname 

Testing local arraylist

Hostname
--------
newname 
newname 

Suddenly I am back to passing by reference again. This is driving me mad! Please help!

Community
  • 1
  • 1
Damartala
  • 1
  • 3

1 Answers1

0

When you enumerate the array by calling foreach, you are getting copies of the content and any changes will get discarded. As Mathias Jessen mentioned you can use a for loop to make changes to the arraylist.

EDIT 2016-12-16 Okay, I looked into it and the arraylist clone method does not work like you and I thought it does. According to MSDN, it returns a shallow copy, i.e. it "copies only the elements of the collection, whether they are reference types or value types, but it does not copy the objects that the references refer to". You and I where both assuming that clone would produce what is called a "deep copy".

In your original example using the basic datatype Int32, deep and shallow copy are the same thing, while in your updated example using PSObjects, they are not and only the references are copied. A method to deep clone objects is found in this thread.

I did not find documentation on this, but it seems as if foreach would do shallow copies also:

$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

Hope this helps.

Community
  • 1
  • 1
josges
  • 1
  • 3
  • Hi, thank you for your fast replies, @Mathias R. Jessen and josges. Sorry, but I could not follow this up earlier. The for-loop works as expected, but not if I am using objects?? I have added this issue to my original post because I could not fit it into a comment. Have you got any idea on this, too? Thank you! – Damartala Dec 14 '16 at 20:20