You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PowerShell递归合并对象并追加数组时遇递归循环问题求助

PowerShell 对象递归合并:数组追加与深层递归修复

需求与问题

需要实现两个对象的递归合并,规则如下:

  • 数组类型:将源对象的数组追加到目标对象的数组末尾
  • 非数组类型:直接用源对象的值替换目标对象对应属性
  • 递归处理深层嵌套结构,避免顶层直接替换

当前代码存在两个核心问题:

  1. 陷入递归循环,疑似递归逻辑判断有误
  2. 无法递归处理深层嵌套的数组(比如示例中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

问题分析

  1. 递归类型判断不全:原代码只处理Hashtable类型的递归,但示例中使用的是PSCustomObject,导致深层嵌套的自定义对象无法触发递归,直接进入替换分支,丢失深层合并逻辑。
  2. 递归参数缺失:递归调用时未传递-replaceArrays参数,导致深层数组无法应用追加规则。
  3. 空属性风险:当目标对象不存在源对象的属性时,直接访问$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被替换为源对象的test1
  • value2保留目标对象的test2
  • value3下的test1保留,test2被替换为test3,array变为asd2, asd3
  • 顶层array追加后包含svejsan, {asd2=value2; anotherarray=test1}, hejsan, {asd1=value1; anotherarray=test1}

内容的提问来源于stack exchange,提问作者jinithin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 21:07:16