Как создать новый экземпляр клона объекта PSObject - PullRequest
19 голосов
/ 06 марта 2012

Я хочу создать новый экземпляр моего пользовательского PSObject.У меня есть объект Button, созданный как PSObject, и я хочу создать новый объект Button2, который имеет те же члены, что и Button, но я не могу найти способ клонировать исходный объект без ссылки на него в исходном объекте (если я изменяюсвойство в Button2 также изменяется в Button).Есть ли способ сделать это так же, как с хеш-таблицами и массивами через какой-то метод Clone ()?

Ответы [ 8 ]

58 голосов
/ 07 ноября 2012

Самый простой способ - использовать Копировать Метод PsObject ==> $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
14 голосов
/ 06 марта 2012

Другая возможность:

 $o1 = New-Object PsObject -Property @{ prop1='a' ; prop2='b' }
 $o2 = $o1 | select *
 $o2.prop1 = 'newvalue'
 $o1.prop1
 $o2.prop1
 a
 newvalue
11 голосов
/ 06 марта 2012

Действительно нет метода клонирования!Однако там, где есть желание ...

$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      
10 голосов
/ 30 августа 2016

По какой-то причине PSObject.Copy () не работает для всех типов объектов.Другое решение для создания копии объекта состоит в том, чтобы преобразовать его в / из 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
2 голосов
/ 05 ноября 2018

Вот пример [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
0 голосов
/ 15 июля 2019

Основываясь на ответе @TeraFlux, вот функция, которая выполняет глубокое копирование нескольких объектов и принимает входные данные конвейера.

Обратите внимание, что она использует преобразование json с глубиной по умолчанию 100, что придает ейс некоторыми слабостями

  • Это будет медленно на глубоких или сложных объектах или объектах с дорогими (медленными) псевдосвойствами ( методы , претендующие на свойства, которые рассчитываются на летупри запросе)
    • Хотя это все равно должно быть быстрее, чем подход 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
0 голосов
/ 12 июля 2019

Начиная с 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       

-> Шаблон из класса безопасен

0 голосов
/ 26 мая 2017

Поместите это в класс Utility или определите его в текущем разделе

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

Использование:

$clonedobj = clone $obj

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...