PowerShell递归合并对象并追加数组时遇递归循环问题求助
PowerShell 对象递归合并:数组追加与深层递归修复
需求与问题
需要实现两个对象的递归合并,规则如下:
- 数组类型:将源对象的数组追加到目标对象的数组末尾
- 非数组类型:直接用源对象的值替换目标对象对应属性
- 递归处理深层嵌套结构,避免顶层直接替换
当前代码存在两个核心问题:
- 陷入递归循环,疑似递归逻辑判断有误
- 无法递归处理深层嵌套的数组(比如示例中
value3下的array子数组未被正确追加)
原问题代码
function Merge-Objects { Param( # Do not append to array. Replace it instead. [bool]$replaceArrays = $false, # Source object (the data that will be merged) [Parameter(Mandatory = $true)] [object]$source, # Target object (where the data will be merged) [Parameter(Mandatory = $true)] [object]$target ) ForEach ($child in $source.PSObject.Properties) { # Set basic variables $childName = $child.Name $childValue = $child.Value $childType = $source.$childName.GetType().Name # If the item is a table, iterate further If ($childType -eq 'Hashtable' -and ` $target.${childName}.GetType().Name -eq 'Hashtable') { $target.$childName = Merge-Objects -source $childValue -target $target.$childName } # If the object is an array, append or replace depending on parameters ElseIf ($childValue -is [array] -and ` $target.$childName -is [array] -and ` $replaceArrays -eq $false) { $target.$childName = $source.$childName + $target.$childName } # If none of the above, then replace/add the item Else { $target.$childName = $childValue } } Return $target } $object1 = [PSCustomObject]@{ value1 = "test1" value3 = @{ test2 = "test3" array = @( "asd3" ) } array = @( "hejsan" @{ asd1 = "value1" anotherarray = @( "test1" ) } ) } $object2 = [PSCustomObject]@{ value1 = "value3" value2 = "test2" value3 = @{ test1 = "test1" test2 = "test2" array = @( "asd2" ) } array = @( "svejsan" @{ asd2 = "value2" anotherarray = @( "test1" ) } ) } # Merge the objects recursively Merge-Objects -source $object1 -target $object2
问题分析
- 递归类型判断不全:原代码只处理
Hashtable类型的递归,但示例中使用的是PSCustomObject,导致深层嵌套的自定义对象无法触发递归,直接进入替换分支,丢失深层合并逻辑。 - 递归参数缺失:递归调用时未传递
-replaceArrays参数,导致深层数组无法应用追加规则。 - 空属性风险:当目标对象不存在源对象的属性时,直接访问
$target.$childName会报错,缺少空值判断。
修复后的代码
function Merge-Objects { Param( [bool]$replaceArrays = $false, [Parameter(Mandatory = $true)] [object]$source, [Parameter(Mandatory = $true)] [object]$target ) foreach ($child in $source.PSObject.Properties) { $childName = $child.Name $childValue = $child.Value # 检查目标对象是否存在当前属性 $targetHasProperty = $target.PSObject.Properties[$childName] -ne $null # 递归处理嵌套对象:同时支持PSCustomObject和Hashtable if (($childValue -is [PSCustomObject] -or $childValue -is [Hashtable]) -and $targetHasProperty) { $targetValue = $target.$childName if ($targetValue -is [PSCustomObject] -or $targetValue -is [Hashtable]) { $target.$childName = Merge-Objects -source $childValue -target $targetValue -replaceArrays $replaceArrays continue } } # 数组追加逻辑:判断双方都是数组且不替换 if (-not $replaceArrays -and $childValue -is [array] -and $targetHasProperty -and $target.$childName -is [array]) { $target.$childName = $target.$childName + $childValue continue } # 其他情况:直接替换或新增属性 $target.$childName = $childValue } return $target } # 测试代码 $object1 = [PSCustomObject]@{ value1 = "test1" value3 = @{ test2 = "test3" array = @( "asd3" ) } array = @( "hejsan" @{ asd1 = "value1" anotherarray = @( "test1" ) } ) } $object2 = [PSCustomObject]@{ value1 = "value3" value2 = "test2" value3 = @{ test1 = "test1" test2 = "test2" array = @( "asd2" ) } array = @( "svejsan" @{ asd2 = "value2" anotherarray = @( "test1" ) } ) } # 执行合并 Merge-Objects -source $object1 -target $object2
关键改动说明
- 扩展递归类型:同时支持
PSCustomObject和Hashtable的深层递归,覆盖常见的嵌套对象类型 - 传递递归参数:将
-replaceArrays参数传递到递归调用,保证深层数组的追加规则一致 - 增加属性存在判断:避免目标对象不存在对应属性时的访问错误
- 调整数组追加顺序:将目标数组放在前面,保证源数组追加到目标数组末尾(符合需求描述)
- 优化逻辑分支:使用
continue减少嵌套层级,提升代码可读性
合并结果验证
执行后,合并后的对象会符合预期:
value1被替换为源对象的test1value2保留目标对象的test2value3下的test1保留,test2被替换为test3,array变为asd2, asd3- 顶层
array追加后包含svejsan, {asd2=value2; anotherarray=test1}, hejsan, {asd1=value1; anotherarray=test1}
内容的提问来源于stack exchange,提问作者jinithin
相关产品推荐
相关产品推荐

