Как добавить System.Collections.ArrayList в пользовательский объект PowerShell? - PullRequest
0 голосов
/ 14 сентября 2018

Моя цель - создать пользовательский объект данных, который имеет две дискретные переменные (fooName и fooUrl) и список fooChildren, каждый элемент списка имеет две переменные дискретных переменных childAge и childName.

В настоящее время у меня есть это:

$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?

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

Ну, я не уверен, что проблема, которую вы получаете, это прекрасно работает для меня

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
0 голосов
/ 14 сентября 2018

Задача состоит в том, чтобы добавить копию экземпляра $fooChild [pscustomobject], который вы повторно используете каждый раз, когда добавляете в список с .Add() (если вы не используете копию, вы получите все элементы списка, указывающие на тот же объект).

Однако, вы не можете клонироватьсуществующий [pscustomobject] (он же [psobject]) экземпляр с New-Object PSObject -Property.

Один из вариантов (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

A немного более неясная альтернатива isпридерживаться $fooChild в качестве [pscustomobject] экземпляра и вызвать .psobject.Copy() на нем для создания клона.


Полезный ответ ArcSet предоставляетболее модульное решение, которое создает новые экземпляры пользовательских объектов по запросу с помощью вспомогательной функции .


Наконец, в 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], просто приведя хеш-таблицу, в которой есть записи, соответствующие именам свойств класса.

0 голосов
/ 14 сентября 2018

Быстрое копирование вставки из того, что у меня есть, которое я использую для создания некоторых из моих массивов. Я должен создать пользовательские объекты и затем добавить их в массив. Его нужно будет изменить для вашего сценария, но я думаю, что он даст вам то, что вам нужно.

[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
}

Отредактировано, чтобы показать, как массив был изначально создан.

...