【问题标题】:How do I add a System.Collections.ArrayList to a PowerShell custom object?如何将 System.Collections.ArrayList 添加到 PowerShell 自定义对象?
【发布时间】:2025-11-29 08:55:01
【问题描述】:

我的目标是创建一个自定义数据对象,其中包含两个离散变量(fooNamefooUrl)和一个 fooChildren 列表,每个列表项都有两个离散变量变量 childAgechildName

目前,我有这个:

$fooCollection = [PSCustomObject] @{fooName=""; fooUrl=""; fooChildrenList=@()} 

$fooCollection.fooName = "foo-a-rama"
$fooCollection.fooUrl = "https://1.2.3.4"

$fooChild = New-Object -TypeName PSobject
$fooChild | Add-Member -Name childAge -MemberType NoteProperty -Value 6
$fooChild | Add-Member -Name childName -MemberType NoteProperty -Value "Betsy"
$fooCollection.fooChildrenList += $fooChild

$fooChild = New-Object -TypeName PSobject
$fooChild | Add-Member -Name childAge -MemberType NoteProperty -Value 10
$fooChild | Add-Member -Name childName -MemberType NoteProperty -Value "Rolf"
$fooCollection.fooChildrenList += $fooChild

cls
$fooCollection.fooName
$fooCollection.fooUrl

foreach ($fooChild in $fooCollection.fooChildrenList)
{
    ("  " + $fooChild.childName + " " + $fooChild.childAge)
}

这会产生以下内容。到目前为止一切顺利

foo-a-rama
https://1.2.3.4
  Betsy 6
  Rolf 10

问题:我不喜欢使用+=,因为据我了解,使用+= 会导致每次都创建$fooCollection.fooChildrenList 的副本(无论处于何种状态) += 被执行。

因此,我不想将fooChildrenList 实现为@(),而是将fooChildrenList 实现为New-Object System.Collections.ArrayList,以便我可以根据需要添加每一行。我在代码中尝试了各种方法,但 fooChildrenList 最终无人居住。例如:

$fooCollection = [PSCustomObject] @{fooName=""; fooUrl=""; fooChildrenList = New-Object System.Collections.ArrayList} 

$fooCollection.fooName = "foo-a-rama"
$fooCollection.fooUrl = "https://1.2.3.4"

$fooChild.childName = "Betsy"
$fooChild.childAge = 6
$fooCollection.fooChildrenList.Add((New-Object PSObject -Property $fooChild))

$fooChild.childName = "Rolf"
$fooChild.childAge = 10
$fooCollection.fooChildrenList.Add((New-Object PSObject -Property $fooChild))

$fooCollection | get-member 显示

TypeName: System.Management.Automation.PSCustomObject

Name            MemberType   Definition                                   
----            ----------   ----------                                   
Equals          Method       bool Equals(System.Object obj)               
GetHashCode     Method       int GetHashCode()                            
GetType         Method       type GetType()                               
ToString        Method       string ToString()                            
fooChildrenList NoteProperty System.Collections.ArrayList fooChildrenList=
fooName         NoteProperty string fooName=foo-a-rama                    
fooUrl          NoteProperty string fooUrl=https://1.2.3.4  

$fooCollection 显示

fooName         : foo-a-rama
fooUrl          : https://1.2.3.4
fooChildrenList : {} 

如何将 System.Collections.ArrayList 添加到 PowerShell 自定义对象?

【问题讨论】:

    标签: powershell arraylist pscustomobject


    【解决方案1】:

    嗯,我不确定你遇到了什么问题,它对我来说很好

    function New-Child([string]$Name, [int]$Age){
        $Child = New-Object -TypeName PSobject
        $Child | Add-Member -Name childAge -MemberType NoteProperty -Value $age -PassThru | 
        Add-Member -Name childName -MemberType NoteProperty -Value $name
        return $child
    }
    
    $fooCollection = [PSCustomObject] @{fooName=""; fooUrl=""; fooChildrenList = New-Object System.Collections.ArrayList} 
    
    $fooCollection.fooName = "foo-a-rama"
    $fooCollection.fooUrl = "https://1.2.3.4"
    $fooCollection.fooChildrenList.Add((New-Child -Name "Betty" -Age 9)) | Out-Null
    $fooCollection.fooChildrenList.Add((New-Child -Name "Ralf" -Age 15)) | Out-Null
    
    $fooCollection.fooName
    $fooCollection.fooUrl
    foreach ($fooChild in $fooCollection.fooChildrenList)
    {
        "  " + $fooChild.childName + " " + $fooChild.childAge
    }
    

    输出

    foo-a-rama
    https://1.2.3.4
      Betty 9
      Ralf 15
    

    【讨论】:

    • 我和你在同一个球场,但我必须假设我试图创建新的“子”对象的方式是问题(请参阅标题下的代码 问题 在我上面的原始帖子中)。无论如何,您的解决方案都有效。我在下面的回答似乎有点模仿你的:-)
    • @NovaSysEng:您的代码的即时问题 - 如已发布 - 是您无法将现有的 [pscustomobject] / [psobject] 实例传递给 New-Object PSObject -Property 所以至于创建它的副本;潜在的概念问题是,如果你创建一个副本,你最终会得到一个列表,其元素都指向同一个对象。 ArcSet 的答案通过确保在调用函数New-Child 时返回一个new 自定义对象实例来避免这个问题。鉴于您自己的答案,听起来每次都添加同一个对象确实是您真正的问题。
    • 我很想说我的答案是正确的……尽管我的答案是正确的。 @Mklement0 的答案更容易理解,并提供了比我的更有用的信息:) 但感谢您接受我的。但你可能想接受 Mklement0 的
    【解决方案2】:

    挑战是在每次添加到列表时添加一个 复制 $fooChild [pscustomobject] 实例重复使用.Add() (如果你不使用副本,你最终会得到所有列表元素都指向相同的对象)。

    但是,您不能使用New-Object PSObject -Property 克隆现有的[pscustomobject](又名[psobject])实例

    一种选择 (PSv3+) 是将可重用的$fooChild 定义为有序哈希表,然后使用[pscustomobject] cast,每次都会隐式创建一个新对象:

    $fooCollection = [PSCustomObject] @{ fooChildrenList = New-Object Collections.ArrayList } 
    
    # Create the reusable $fooChild as an *ordered hashtable* (PSv3+)
    $fooChild = [ordered] @{ childName = ''; childAge = -1 }
    
    # Create 1st child and add to list with [pscustomobject] cast
    $fooChild.childName = 'Betsy'; $fooChild.childAge = 6
    $null = $fooCollection.fooChildrenList.Add([pscustomobject] $fooChild)
    
    # Create and add another child.
    $fooChild.childName = 'Rolf'; $fooChild.childAge = 10
    $null = $fooCollection.fooChildrenList.Add([pscustomobject] $fooChild)
    
    # Output the children
    $fooCollection.fooChildrenList
    

    注意$null = ...,它会抑制来自.Add() 方法调用的通常不需要的输出。

    以上产量:

    childName childAge
    --------- --------
    Betsy            6
    Rolf            10
    

    一个稍微模糊的替代方法是坚持使用$fooChild 作为[pscustomobject] 实例并在其上调用.psobject.Copy() 以创建克隆。


    ArcSet's helpful answer 提供了一个更加模块化的解决方案,它通过帮助函数按需创建新的自定义对象实例。


    最后,在 PSv5+ 中,您可以定义一个帮助器class

    $fooCollection = [PSCustomObject] @{ fooChildrenList = New-Object Collections.ArrayList } 
    
    # Define helper class
    class FooChild {
      [string] $childName
      [int]    $childAge
    }
    
    # Create 1st child and add to list with [pscustomobject] cast
    $null = $fooCollection.fooChildrenList.Add([FooChild] @{ childName = 'Betsy'; childAge = 6 })
    
    # Create and add another child.
    $null = $fooCollection.fooChildrenList.Add([FooChild] @{ childName = 'Rolf'; childAge = 10 })
    
    # Output the children
    $fooCollection.fooChildrenList
    

    注意[FooChild] 的实例如何通过简单地强制转换具有与类属性名称匹配的条目的哈希表来创建。

    【讨论】:

      【解决方案3】:

      从我用来制作一些数组的东西中快速复制粘贴。我必须创建自定义对象,然后将它们添加到数组中。它需要针对您的场景进行修改,但我认为它会为您提供所需的内容。

      [System.Collections.ArrayList]$SQL_Query_Results = @()
      
      ForEach ($SQL_Index in $SQL_Table) {
      
          $SQL_Array_Object = [PSCustomObject]@{
              'Computer_Name'    = $SQL_Table[$SQL_Index_Counter].ComputerID -replace ",", ""
              'Project'          = $SQL_Table[$SQL_Index_Counter].Project
              'Site'             = $SQL_Table[$SQL_Index_Counter].Site
              'Description'      = $SQL_Table[$SQL_Index_Counter].Description -replace ",", ""
              'Physical_Machine' = $SQL_Table[$SQL_Index_Counter].IsPhysicalMachine
              'Active'           = $SQL_Table[$SQL_Index_Counter].IsActive
          }
      
          $SQL_Query_Results.Add($SQL_Array_Object) | Out-Null
      }
      

      编辑显示数组最初是如何创建的。

      【讨论】:

      • 我假设 $SQL_Query_Results 被定义为 $SQL_Query_Results = New-Object System.Collections.ArrayList ?
      • [System.Collections.ArrayList]$SQL_Query_Results = @() 是我最初的创作方式
      • $SQL_Table 的类型是什么,$SQL_Index_Counter 来自哪里(如$SQL_Table[$SQL_Index_Counter].ComputerID -replace ",", "")? (我没有看到 $SQL_Index_Counter 初始化或递增)
      • 对于那个特定的场景,都是String,但我也使用过Intbooldatetime等。当您将其存储在 PSCustomObject 中时,它将是您定义的内容
      • 抱歉,我刚刚意识到 - 我正在尝试在 PSCustomObject 中实现 System.Collections.ArrayList(或者避免使用 +=)。这个例子并没有破解那个坚果
      最近更新 更多