将 Powershell PSCustomObject 复制到数组元素将传递引用,而不是值

Copying Powershell PSCustomObject to array element will pass reference, not value

不确定我做错了什么,但是在将 Powershell 中的 PSCustomObject 复制到数组元素时,这是通过引用复制的。 看到这个:

$body = [PSCustomObject]@{ 
    albumId = $album_id;
    newMediaItems = [PSCustomObject]@()    
} 

$mediaItem = [PSCustomObject]@{
    description = "";
    simpleMediaItem = [PSCustomObject]@{ 
        fileName = "";
        uploadToken = "";
        }
}

$mediaItem.description = "Friend of Mickey Mouse"
$mediaItem.simpleMediaItem.fileName = "Goofy.txt"
$mediaItem.simpleMediaItem.uploadToken = "1111"

$body.newMediaItems += $mediaItem.PsObject.Copy()

$mediaItem.description = "Friend of Rocker Duck"
$mediaItem.simpleMediaItem.fileName = "Donald Duck.txt"
$mediaItem.simpleMediaItem.uploadToken = "2222"

$body.newMediaItems +=  $mediaItem.PsObject.Copy()


$body | ConvertTo-Json -depth 4

输出:

{
  "albumId": null,
  "newMediaItems": [
    {
      "description": "Friend of Mickey Mouse",
      "simpleMediaItem": {
        "fileName": "Donald Duck.txt",
        "uploadToken": "2222"
      }
    },
    {
      "description": "Friend of Rocker Duck",
      "simpleMediaItem": {
        "fileName": "Donald Duck.txt",
        "uploadToken": "2222"
      }
    }
  ]
} 

.psobject.Copy()[pscustomobject] 个实例执行 (成员方面)克隆。

由于您的 simpleMediaItem 属性 包含对 .NET 引用类型 的引用(恰好是另一个 [pscustomobject] 实例),复制的是 reference,因此原始 [pscustomobject] 和通过 .psobject.Copy() 获得的克隆都引用 完全相同的对象.

对于深度(递归)克隆(没有通用解决方案),您必须创建自定义实现。

您可以使用自定义 class 定义完全避免该问题:

class MediaItem {
  [string] $description
  [pscustomobject] $simpleMediaItem = [pscustomobject] @{ 
      fileName = ""
      uploadToken = ""
  }
}

现在,每次需要一个新的独立实例时,您只需使用 [MediaItem]::new()

总而言之:

class MediaItem {
  [string] $description
  [pscustomobject] $simpleMediaItem = [pscustomobject] @{ 
    fileName    = ""
    uploadToken = ""
  }
}

$body = [PSCustomObject]@{ 
  albumId       = $album_id;
  newMediaItems = @()    
} 

# Create a new instance.
$mediaItem = [MediaItem]::new()
$mediaItem.description = "Friend of Mickey Mouse"
$mediaItem.simpleMediaItem.fileName = "Goofy.txt"
$mediaItem.simpleMediaItem.uploadToken = "1111"

$body.newMediaItems += $mediaItem

# Create a new instance.
$mediaItem = [MediaItem]::new()
$mediaItem.description = "Friend of Rocker Duck"
$mediaItem.simpleMediaItem.fileName = "Donald Duck.txt"
$mediaItem.simpleMediaItem.uploadToken = "2222"

$body.newMediaItems += $mediaItem

$body | ConvertTo-Json -Depth 4  

您所看到的是预料之中的,您只是在复制基础对象。我还建议您使用 functionclass 来执行此操作,这样会容易得多,而且不需要复制。

$body = [PSCustomObject]@{ 
    albumId = $album_id;
    newMediaItems = [PSCustomObject]@()    
} 
$mediaItem = [PSCustomObject]@{
    description = "";
    simpleMediaItem = [PSCustomObject]@{ 
        fileName = "";
        uploadToken = "";
    }
}
$mediaItem.description = "Friend of Mickey Mouse"
$mediaItem.simpleMediaItem.fileName = "Goofy.txt"
$mediaItem.simpleMediaItem.uploadToken = "1111"

$body.newMediaItems += $mediaItem

$base = $mediaItem.PsObject.Copy()
$child = $mediaItem.simpleMediaItem.PSObject.Copy()

$base.description = "Friend of Rocker Duck"
$child.fileName = "Donald Duck.txt"
$child.uploadToken = "2222"
$base.simpleMediaItem = $child

$body.newMediaItems += $base