从函数返回 PSObjects 的 ArrayList 时的空白记录
Blank records when returning ArrayList of PSObjects from function
所以我正在重构一个 Powershell 脚本并将很多东西移到函数中。当我 return 一个包含 42 PS 个对象的 ArrayList 时,来自函数(称为 Get-OutList)的 return $out
,42 条空白记录被插入到 ArrayList 的开头,然后我的原始记录关注
我的函数如下所示:
function Get-OutList {
param (
[Parameter(Position=0,mandatory=$true)]
[PSObject]$RoleCollection,
[Parameter(Position=1,mandatory=$true)]
[PSObject]$MemberCollection
)
$out = New-Object System.Collections.ArrayList
$MemberCollection.result | ForEach-Object {
$currentMember = $_
$memberDetail = New-Object PSObject
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name FirstName -Value $($currentMember.user.first_name)
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name LastName -Value $($currentMember.user.last_name)
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Email -Value $($currentMember.user.email)
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Status -Value $($currentMember.status)
$RoleCollection.result | ForEach-Object {
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name $_.name -Value (&{If($currentMember.roles.name -contains $_.name){"Y"}Else{""}})
}
$out.Add($memberDetail)
}
return $out
}
我了解 Powershell 将每条记录枚举回调用函数的位置,但我尝试了一些方法都无济于事:
- PS v5.1.x 和 v7.3.0.
中的行为相同
- 返回
return @($out)
没有区别(即结果 System.Object 有 42 条空白记录,然后是我的 42 条原始记录,总共 84 条记录)。
- 返回
return Write-Output -NoEnumerate $out
结果 System.Object 有 42 条空白记录,我的 42 条原始记录嵌套在第 43 条记录中。
- 将函数调用的结果键入 ArrayList 与
$results = [System.Collections.ArrayList](Get-OutList)
没有区别。
为什么我不能让我的对象与从函数 returned 之前一样?如有任何帮助,我们将不胜感激!
编辑#1
包括一个易于重现的示例:
function Get-OutList {
param (
[Parameter(Position=0,mandatory=$true)]
[PSObject]$MemberCollection
)
$out = New-Object 'System.Collections.ArrayList'
$MemberCollection | ForEach-Object {
$memberDetail = New-Object PSObject
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name FirstName -Value "One"
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name LastName -Value "Two"
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Email -Value "Three"
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Status -Value "Four"
$out.Add($memberDetail)
}
return $out
}
$members = @("Joe Bloggs", "Some Dude", "The Dude")
$memberDetails = Get-OutList -MemberCollection $members
Write-Output $memberDetails
如果你在 $out 传回之前添加一个断点,你会看到有 3 条记录,如果你继续步进,你应该看到 $memberDetails 将有 6 条记录(前 3 条空白)。
编辑 #2
使用 Generic.List 而不是 ArrayList 时似乎没有这样的问题。使用 $out = [System.Collections.Generic.List[PSObject]]::new()
而不是 $out = New-Object 'System.Collections.ArrayList'
,它工作得很好。
使用 $out = [System.Collections.Generic.List[PSObject]]::new()
而不是 $out = New-Object 'System.Collections.ArrayList'
,它工作得很好。没有多余的毯子。
您的问题源于 System.Collections.ArrayList.Add()
方法具有 return 值(索引添加对象的位置)并且 return 值 成为函数“return 值”的一部分,即 输出对象流 .
这是 PowerShell 的 隐式输出行为 的表现形式,在 .
中进行了解释
值得注意的是,return
不是 在 PowerShell 中从函数生成 output 所必需的 - 任何语句都可以生成输出。 return $foo
只是 Write-Output $foo; return
的语法糖,或者依赖于 隐式 输出行为,$foo; return
因此,立即修复你的问题是丢弃(抑制)你的隐式输出$out.Add($memberDetail)
调用,这通常是通过将调用分配给$null
来完成的(还有其他方法,在中讨论):
# Discard the unwanted output from .Add()
$null = $out.Add($memberDetail)
, you indirectly applied that fix by switching to the System.Collections.Generic.List`1
列表类型,其.Add()
方法有无return值。正是出于这个原因,以及 强类型 列表元素的能力,System.Collections.Generic.List`1
通常优于 System.Collections.ArrayList
退一步:
在像您这样的简单情况下,整个函数输出将被捕获在一个列表中,您可以利用 output-stream 行为并简单地 发出每个输出对象 单独 从您的函数(从ForEach-Object
脚本块)和让PowerShell 收集单个对象list-like 数据结构中的 emitted,它将是一个常规的 PowerShell array,即 [object[]
类型(即 fixed-size 类似于 System.Collections.ArrayList
):
这样不仅更方便,而且性能也更好。
应用于您的示例函数:
function Get-OutList {
param (
[Parameter(Position=0,mandatory=$true)]
[PSObject]$MemberCollection
)
$MemberCollection | ForEach-Object {
$first, $last = -split $_
# Construct and implicitly output a custom object.
[pscustomobject] @{
FirstName = $first
LastName = $last
Email = 'Three'
Status = 'Four'
}
}
# No need for `return` - all output objects were emitted above.
}
$members = @("Joe Bloggs", "Some Dude", "The Dude")
# By assigning the function's output stream to a variable,
# the individual output objects are automatically collected in an array
# (assuming *two or more* output objects; if you want an array even if
# only *one* object is output, use [Array] $memberDetails = ...)
$memberDetails = Get-OutList -MemberCollection $members
# Output (implicitly).
$memberDetails
另请注意使用 [pscustomobject] @{ ... }
语法糖来简化 custom-object 创建 - 请参阅概念性 about_Object_Creation 帮助主题。
所以我正在重构一个 Powershell 脚本并将很多东西移到函数中。当我 return 一个包含 42 PS 个对象的 ArrayList 时,来自函数(称为 Get-OutList)的 return $out
,42 条空白记录被插入到 ArrayList 的开头,然后我的原始记录关注
我的函数如下所示:
function Get-OutList {
param (
[Parameter(Position=0,mandatory=$true)]
[PSObject]$RoleCollection,
[Parameter(Position=1,mandatory=$true)]
[PSObject]$MemberCollection
)
$out = New-Object System.Collections.ArrayList
$MemberCollection.result | ForEach-Object {
$currentMember = $_
$memberDetail = New-Object PSObject
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name FirstName -Value $($currentMember.user.first_name)
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name LastName -Value $($currentMember.user.last_name)
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Email -Value $($currentMember.user.email)
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Status -Value $($currentMember.status)
$RoleCollection.result | ForEach-Object {
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name $_.name -Value (&{If($currentMember.roles.name -contains $_.name){"Y"}Else{""}})
}
$out.Add($memberDetail)
}
return $out
}
我了解 Powershell 将每条记录枚举回调用函数的位置,但我尝试了一些方法都无济于事:
- PS v5.1.x 和 v7.3.0. 中的行为相同
- 返回
return @($out)
没有区别(即结果 System.Object 有 42 条空白记录,然后是我的 42 条原始记录,总共 84 条记录)。 - 返回
return Write-Output -NoEnumerate $out
结果 System.Object 有 42 条空白记录,我的 42 条原始记录嵌套在第 43 条记录中。 - 将函数调用的结果键入 ArrayList 与
$results = [System.Collections.ArrayList](Get-OutList)
没有区别。
为什么我不能让我的对象与从函数 returned 之前一样?如有任何帮助,我们将不胜感激!
编辑#1 包括一个易于重现的示例:
function Get-OutList {
param (
[Parameter(Position=0,mandatory=$true)]
[PSObject]$MemberCollection
)
$out = New-Object 'System.Collections.ArrayList'
$MemberCollection | ForEach-Object {
$memberDetail = New-Object PSObject
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name FirstName -Value "One"
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name LastName -Value "Two"
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Email -Value "Three"
Add-Member -InputObject $memberDetail -MemberType NoteProperty -Name Status -Value "Four"
$out.Add($memberDetail)
}
return $out
}
$members = @("Joe Bloggs", "Some Dude", "The Dude")
$memberDetails = Get-OutList -MemberCollection $members
Write-Output $memberDetails
如果你在 $out 传回之前添加一个断点,你会看到有 3 条记录,如果你继续步进,你应该看到 $memberDetails 将有 6 条记录(前 3 条空白)。
编辑 #2
使用 Generic.List 而不是 ArrayList 时似乎没有这样的问题。使用 $out = [System.Collections.Generic.List[PSObject]]::new()
而不是 $out = New-Object 'System.Collections.ArrayList'
,它工作得很好。
使用 $out = [System.Collections.Generic.List[PSObject]]::new()
而不是 $out = New-Object 'System.Collections.ArrayList'
,它工作得很好。没有多余的毯子。
您的问题源于 System.Collections.ArrayList.Add()
方法具有 return 值(索引添加对象的位置)并且 return 值 成为函数“return 值”的一部分,即 输出对象流 .
这是 PowerShell 的 隐式输出行为 的表现形式,在
值得注意的是,return
不是 在 PowerShell 中从函数生成 output 所必需的 - 任何语句都可以生成输出。 return $foo
只是 Write-Output $foo; return
的语法糖,或者依赖于 隐式 输出行为,$foo; return
因此,立即修复你的问题是丢弃(抑制)你的隐式输出$out.Add($memberDetail)
调用,这通常是通过将调用分配给$null
来完成的(还有其他方法,在
# Discard the unwanted output from .Add()
$null = $out.Add($memberDetail)
System.Collections.Generic.List`1
列表类型,其.Add()
方法有无return值。正是出于这个原因,以及 强类型 列表元素的能力,System.Collections.Generic.List`1
通常优于 System.Collections.ArrayList
退一步:
在像您这样的简单情况下,整个函数输出将被捕获在一个列表中,您可以利用 output-stream 行为并简单地 发出每个输出对象 单独 从您的函数(从ForEach-Object
脚本块)和让PowerShell 收集单个对象list-like 数据结构中的 emitted,它将是一个常规的 PowerShell array,即 [object[]
类型(即 fixed-size 类似于 System.Collections.ArrayList
):
这样不仅更方便,而且性能也更好。
应用于您的示例函数:
function Get-OutList {
param (
[Parameter(Position=0,mandatory=$true)]
[PSObject]$MemberCollection
)
$MemberCollection | ForEach-Object {
$first, $last = -split $_
# Construct and implicitly output a custom object.
[pscustomobject] @{
FirstName = $first
LastName = $last
Email = 'Three'
Status = 'Four'
}
}
# No need for `return` - all output objects were emitted above.
}
$members = @("Joe Bloggs", "Some Dude", "The Dude")
# By assigning the function's output stream to a variable,
# the individual output objects are automatically collected in an array
# (assuming *two or more* output objects; if you want an array even if
# only *one* object is output, use [Array] $memberDetails = ...)
$memberDetails = Get-OutList -MemberCollection $members
# Output (implicitly).
$memberDetails
另请注意使用 [pscustomobject] @{ ... }
语法糖来简化 custom-object 创建 - 请参阅概念性 about_Object_Creation 帮助主题。