如何创建PSObject对象的新克隆实例

时间:2012-03-06 10:12:46

标签: powershell

我想创建自定义PSObject的新实例。我有一个创建为PSObject的Button对象,我想创建新的对象Button2,它具有与Button相同的成员,但我找不到如何克隆原始对象而不在原始对象中引用它的方法(如果我更改Button2中的属性也在Button中更改。有没有办法如何通过一些Clone()方法与哈希表和数组类似地做到这一点?

10 个答案:

答案 0 :(得分:58)

最简单的方法是使用PsObject ==>的Copy方法$o2 = $o1.PsObject.Copy()

$o1 = New-Object -TypeName PsObject -Property @{
    Fld1 = 'Fld1';
    Fld2 = 'Fld2';
    Fld3 = 'Fld3'}

$o2 = $o1.PsObject.Copy()

$o2 | Add-Member -MemberType NoteProperty -Name Fld4 -Value 'Fld4'
$o2.Fld1 = 'Changed_Fld'

$o1 | Format-List
$o2 | Format-List

输出:

Fld3 : Fld3
Fld2 : Fld2
Fld1 : Fld1

Fld3 : Fld3
Fld2 : Fld2
Fld1 : Changed_Fld
Fld4 : Fld4

答案 1 :(得分:14)

另一种可能性:

 $o1 = New-Object PsObject -Property @{ prop1='a' ; prop2='b' }
 $o2 = $o1 | select *
 $o2.prop1 = 'newvalue'
 $o1.prop1
 $o2.prop1
 a
 newvalue

答案 2 :(得分:11)

确实没有克隆方法!但是如果有遗嘱......

$o = New-Object PsObject -Property @{ prop1='a' ; prop2='b' }
$o2 = New-Object PsObject
$o.psobject.properties | % {
    $o2 | Add-Member -MemberType $_.MemberType -Name $_.Name -Value $_.Value
}
$o.prop1 = 'newvalue'

$o
$o2

输出:

prop2     prop1                                                                 
-----     -----                                                                 
b         newvalue                                                              
b         a      

答案 3 :(得分:9)

由于某种原因,PSObject.Copy()不适用于所有对象类型。另一个创建对象副本的解决方案是将其转换为Json或从Json转换然后将其保存在新变量中:

$CustomObject1 = [pscustomobject]@{a=1; b=2; c=3; d=4}
$CustomObject2 = $CustomObject1 | ConvertTo-Json -depth 100 | ConvertFrom-Json
$CustomObject2 | add-Member -Name "e" -Value "5" -MemberType noteproperty

$CustomObject1 | Format-List
$CustomObject2 | Format-List

答案 4 :(得分:1)

这是一个[pscustomobject]示例,带有隐藏的.psobject.copy():

$a = [pscustomobject]@{message='hi'}
$a.message
hi

$b = $a.psobject.copy()
$b.message
hi

$a.message = 'there'
$a.message
there

$b.message
hi

答案 5 :(得分:0)

将它放在Utility类中或在当前部分中定义

for sublist in matrix[:]:
    for element in sublist[:]:
        ran = random.choice([p_vivo, p_muerto])
        sublist.append(ran)

用法:

function clone($obj) { $newobj = New-Object PsObject $obj.psobject.Properties | % {Add-Member -MemberType NoteProperty -InputObject $newobj -Name $_.Name -Value $_.Value} return $newobj }

答案 6 :(得分:0)

从PowerShell v5开始,您可以使用Class。 psobject.Copy()的问题在于,如果您更新克隆的对象,那么模板对象的引用属性也会被更新。

示例:

function testTemplates
{
    $PSCustomObjectTemplate = New-Object PSCustomObject -Property @{
        List1 = [System.Collections.Generic.List[string]]@()  # will be updated in template
        String1 = "value1" # will not be updated in template
        Bool1 = $false # will not be updated in template
    }

    $objectFromPSTemplate1 = $PSCustomObjectTemplate.psobject.Copy()
    $objectFromPSTemplate1.List1.Add("Value")
    $objectFromPSTemplate1.String1 = "value2" 
    $objectFromPSTemplate.Bool1 = $true 

    # $PSCustomObjectTemplate IS updated, so CANNOT be used as a clean template!
    $PSCustomObjectTemplate

    Class ClassTemplate {
        [System.Collections.Generic.List[string]]$List1 = @() # will not be updated in template
        [string]$String1 = "value1" # will not be updated in template
        [bool]$Bool1 = $false # will not be updated in template
    }
    $objectFromClassTemplate = [ClassTemplate]::new()
    $objectFromClassTemplate.List1.Add("Value")
    $objectFromClassTemplate.String1 = "value2"
    $objectFromClassTemplate.Bool1 = $true

    # $ClassTemplate IS NOT updated, so can be used as a clean template!
    [ClassTemplate]::new()
}

testTemplates

PS C:\Windows\system32> testTemplates

List1   String1 Bool1
-----   ------- -----
{Value} value1  False       

-> PSCustomObject中的模板已更新(引用属性-List1)

List1   String1 Bool1
-----   ------- -----
{}      value1  False       

->“班级”中的模板是安全的

答案 7 :(得分:0)

基于@TeraFlux的答案,此函数可对多个对象进行深层复制并接受管道输入。

请注意,它利用默认深度为100的json转换,使其具有一些弱点

  • 在较深或较复杂的对象上,或者在具有昂贵(较慢)伪属性的对象上(methods假装是在需要时即时计算的属性),它的运行速度会很慢
    • 尽管它应该比Add-Member方法还快,因为繁重的工作正在通过编译函数进行
  • 无法存储在JSON中的任何内容都可能会损坏或被抛弃(方法将是此类错误的主要选择)
    • 尽管可以安全地通过此过程的任何物品都应是可保存的,可以安全地存储(以供回收)或导出以进行运输

我会对处理这些问题的任何警告或改进感兴趣

function Clone-Object 
    {
    [CmdletBinding()]
    Param `
        (
        [Parameter(ValueFromPipeline)] [object[]]$objects,
        [Parameter()] [int] $depth = 100
        )
    $clones = foreach
        ($object in $objects)
        {
        $object | ConvertTo-Json -Compress -depth $depth | ConvertFrom-Json
        }
    return $clones
    }

这是一些非常基本的单元测试

$testClone = `
    {
    $test1 = $null
    $test2 = $null
    $test3 = $null

    $Test1 = [psCustomObject]@{a=1; b=2; c=3; d=4}
    $Test2 = $Test1 | ConvertTo-Json -depth 100 | ConvertFrom-Json
    $Test2 | add-Member -Name "e" -Value "5" -MemberType noteproperty
    $Test3 = $test2 | Clone-Object
    $Test3 | add-Member -Name "f" -Value "6" -MemberType noteproperty
    $Test1.a = 7
    $Test2.a = 8

    #$Expected0 = [psCustomObject]@{a=1; b=2; c=3; d=4}
    $Expected1 = [pscustomobject]@{a=7; b=2; c=3; d=4}
    $Expected2 = [pscustomobject]@{a=8; b=2; c=3; d=4; e=5}
    $Expected3 = [pscustomobject]@{a=1; b=2; c=3; d=4; e=5; f=6}

    $results1 = @(); $results1+=$test1; $results1+=$expected1
    $results2 = @(); $results2+=$test2; $results2+=$expected2
    $results3 = @(); $results3+=$test3; $results3+=$expected3
    $results1 | Format-Table # if these don't match then its probably passing references (copy not clone)
    $results2 | Format-Table # if these don't match the core approach is incorrect
    $results3 | Format-Table # if these don't match the function didn't work

    }
&$testClone

答案 8 :(得分:0)

我发现的更好的方法是使用ConvertTo-Json和ConvertFrom-Json。 e- 假设您要克隆一个对象$ toBeClonedObject,只需在下面的代码中运行即可克隆。

$clonedObject = $toBeClonedObject | ConvertTo-Json | ConvertFrom-Json

答案 9 :(得分:0)

这通常对我有用:

$Source = [PSCustomObject]@{ Value = 'Test' };
$Copy = ($Source | ConvertTo-Json) | ConvertFrom-Json;