PowerShell 空数组初始化在条件变量赋值中失败

Vin*_*ent 1 arrays powershell

在这篇关于如何在 PowerShell 中最好地创建(三元运算符)表达式的文章之后,我尝试将其转换:

if ($condition)
{ 
   $accessList = @() 
}
else
{
    $accessList = $accessControl.AllowedItems
}
Run Code Online (Sandbox Code Playgroud)

进入这个:

$accessList = if ($condition) { @() } else { $accessControl.AllowedItems }
Run Code Online (Sandbox Code Playgroud)

单行代码无法初始化空数组。结果$accessList没有任何数组属性/方法并$NULL -eq $accessList返回True。这个版本也不起作用:

$accessList = $(if ($condition) { @() } else { $accessControl.AllowedItems })
Run Code Online (Sandbox Code Playgroud)

奇怪的是,如果我尝试初始化一个非空数组,单行代码就会起作用。它可能与变量评估和管道的工作原理有关,但在谷歌搜索了一下之后,我发现没有对这种特殊情况的详细解释。请帮助理解其背后的机制。

mkl*_*nt0 5

您需要防止在(隐式使用的)管道中隐式枚举空数组,最简单的解决方案是将其包装在辅助临时数组中,您可以使用数组构造函数,运算符 的一元形式构造该数组:

$accessList = if ($condition) { , @() } else { $accessControl.AllowedItems }
Run Code Online (Sandbox Code Playgroud)

PowerShell 7+提供了一种绕过该问题的方法,即使用?:三元条件运算符,该运算符充当表达式(请参阅下面的说明):

$accessList = $condition ? @() : $accessControl.AllowedItems 
Run Code Online (Sandbox Code Playgroud)

背景资料

区别很微妙:

在:

$accessList = @()
Run Code Online (Sandbox Code Playgroud)

@()是一个表达式,因此按原样分配。

在:

$accessList = if ($condition) { @() }
Run Code Online (Sandbox Code Playgroud)

if ($condition) { @() }是一个完整的语句,因此它的output( @())隐式使用管道,其中隐式枚举数组并将其元素发送到管道;在空数组的情况下,没有什么可枚举的,因此不会输出任何内容(技术上将其表示为[System.Management.Automation.Internal.AutomationNull]::Value单例)。

将数组包装在辅助临时数组中(如顶部所示)使管道仅枚举该辅助数组。数组,因此包装后的数组作为一个整体输出。

这同样适用于命令的输出,特别是如果您尝试从脚本或函数输出整个数组。

但一般来说,请注意 PowerShell 命令不会集合作为一个整体输出,而是枚举它们。

另请注意,如果在管道中枚举两个或多个元素并将输出分配给变量,PowerShell 会隐式将它们收集在数组中[object[]],而单个元素按原样分配(无数组包装器)。请参阅此答案以获取更多信息。