PSObject 개체의 새 복제 인스턴스를 생성하는 방법
사용자 지정 PSObject의 새 인스턴스를 생성하려고 합니다.나는 PSObject로 생성된 Button 객체가 있고 Button과 동일한 멤버를 가진 Button2 객체를 새로 생성하고 싶지만, 원래 객체를 참조하지 않고는 원래 객체를 복제하는 방법을 찾을 수 없습니다(Button2에서 속성을 변경하면 Button에서도 변경됩니다).일부 Clone() 방법을 통해 해시 테이블 및 어레이와 유사하게 수행하는 방법이 있습니까?
가장 쉬운 방법은 의 복사 방법을 사용하는 것입니다.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
어떤 이유에서인지 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
실제로 복제 방법은 없습니다!하지만 의지가 있는 곳이라면...
$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
또 다른 가능성:
$o1 = New-Object PsObject -Property @{ prop1='a' ; prop2='b' }
$o2 = $o1 | select *
$o2.prop1 = 'newvalue'
$o1.prop1
$o2.prop1
a
newvalue
다음은 숨겨진 .psobject.copy()를 사용한 [pscustomobject] 예제입니다.
$a = [pscustomobject]@{message='hi'}
$a.message
hi
$b = $a.psobject.copy()
$b.message
hi
$a.message = 'there'
$a.message
there
$b.message
hi
제가 알아낸 더 나은 방법은 ConvertTo-Json과 ConvertFrom-Json을 사용하는 것이었습니다.Ee - 개체 $를 BeCloneObject로 복제하려면, 복제할 코드 아래에서 실행하면 됩니다.
$clonedObject = $toBeClonedObject | ConvertTo-Json | ConvertFrom-Json
PowerShell v5부터는 Class를 사용할 수 있습니다.psobject에 문제가 있습니다.복사()는 복제된 개체를 업데이트하면 템플릿 개체의 참조 속성도 업데이트됩니다.
예:
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()
}
test 템플릿
PS C:\Windows\system32> testTemplates
List1 String1 Bool1
----- ------- -----
{Value} value1 False
-> PSCustomObject의 템플릿이 업데이트되었습니다(참조 속성 - List1).
List1 String1 Bool1
----- ------- -----
{} value1 False
-> 클래스의 템플릿은 안전합니다.
이것은 일반적으로 저에게 효과가 있습니다.
$Source = [PSCustomObject]@{ Value = 'Test' };
$Copy = ($Source | ConvertTo-Json) | ConvertFrom-Json;
유틸리티 클래스에 넣거나 현재 섹션에서 정의
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
@TeraFlux의 답변을 기반으로 여러 개체에 대해 딥 복사를 수행하고 파이프라인 입력을 수락하는 기능이 있습니다.
참고로 기본 깊이가 100인 json 변환을 활용하므로 몇 가지 약점이 있습니다.
- 깊고 복잡한 객체, 또는 값비싼(느린) 유사 속성을 가진 객체(요청 시 즉시 계산되는 속성인 것처럼 가장하는 방법)에서 속도가 느려집니다.
- 무거운 리프팅이 컴파일된 기능을 거치기 때문에 여전히 멤버 추가 접근 방식보다 빨라야 합니다.
- 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
다른 옵션:
function Copy-Object($Object) {
$copy = @()
$Object.ForEach({
$currentObject = $_
$currentObjectCopy = New-Object $currentObject.GetType().Name
$currentObjectCopy.psobject.Properties.ForEach({
$_.Value = $currentObject.psobject.Properties[($_.Name)].Value
})
$copy += $currentObjectCopy
})
return $copy
}
테스트 개체:
class TestObjectA {
[string]$g
[int[]]$h
[string]getJ(){
return 'j'
}
}
class TestObjectB {
[string]$a
[int]$b
[hashtable]$c
[TestObjectA[]]$d
[string]getI(){
return 'i'
}
}
테스트:
$b = New-Object -TypeName TestObjectB -Property @{
a = 'value a'
b = 2
c = @{ e = 'value e'; f = 3 }
d = New-Object -TypeName TestObjectA -Property @{
g = 'value g'
h = @(4,5,6)
}
}
$bCopy = Copy-Object $b
# test with simple comparison
-not $(Compare-Object $b $bCopy)
True
# test json deep conversion output
$bJson = $b | ConvertTo-Json -Depth 10
$bCopyJson = $bCopy | ConvertTo-Json -Depth 10
-not $(Compare-Object $bJson $bCopyJson)
True
# test methods are intact
$bCopy.getI()
i
$bCopy.d.GetJ()
j
# test objects are seperate instances
$bCopy.b = 3
$b.b
2
$bCopy.b
3
때부터Select-Object -Property
속성 이름에서 와일드카드를 확장합니다. 얕은 복제를 위한 간단한 방법은 다음과 같습니다.
# Set up object
$o1 = [PSCustomObject]@{
Fld1 = 'Fld1';
Fld2 = 'Fld2';
Fld3 = 'Fld3'}
# Clone
$o2 = $o1 | Select-Object -Property *;
# Tests
$o1 -eq $o2;
$o1 | Format-List;
$o2 | Format-List;
Clixml을 사용한 제 버전입니다.
function Get-PSObjectClone {
param ( [psobject] $InputObject )
$_temp = New-TemporaryFile
$InputObject | Export-Clixml -Path $_temp -Depth 100
$_object = Import-Clixml -Path $_temp
Remove-Item $_temp -Force
Write-Output $_object
}
내가 던진 모든 것과 함께 작동합니다.
편집: 저는 실제로 완벽하게 작동하는 것처럼 보이는 훨씬 깨끗한 버전을 생각해냈습니다.
[Management.Automation.PSSerializer]::Deserialize( [Management.Automation.PSSerializer]::Serialize( $InputObject ))
언급URL : https://stackoverflow.com/questions/9581568/how-to-create-new-clone-instance-of-psobject-object
'programing' 카테고리의 다른 글
동적 및 네임스페이스 모듈이 등록되지 않았습니다(vuex-module-decorator, vuex-class). (0) | 2023.07.31 |
---|---|
여러 테이블에 여러 개의 FULL OUTER JOIN(전체 외부 조인 (0) | 2023.07.31 |
Restful API 서비스 (0) | 2023.07.31 |
PowerShell에서 특정 확장자를 가진 파일을 재귀적으로 검색하는 방법은 무엇입니까? (0) | 2023.07.31 |
치명적 오류: 선택적 값의 래핑을 해제하는 동안 예기치 않게 0이(가) 발견되었습니다. (0) | 2023.07.31 |