When checking variables and collections of variables for nullity, comparison operators seem to enumerate collections of size 2 or more:
> if ( @( $null, $null ) -eq $null ) { $True } else { $False }
True
Run Code Online (Sandbox Code Playgroud)
But they do not for collections of size 1:
> if ( @( $null ) -eq $null ) { $True } else { $False }
False
Run Code Online (Sandbox Code Playgroud)
I'm aware that it's best practice to null-compare using the left-hand side ($null -eq @( $null )), but can someone explain what's happening here? I suspect there's something more subtle happening that impacts other code that I write.
Why are these two results different?
tl;博士
在 PowerShell 条件/隐式布尔上下文中:
单元素数组被视为标量:也就是说,它们唯一的元素本身被解释为布尔值。[1]
2+元素数组总是 $true,无论其内容如何。
使用数组作为 LHS,诸如此类的数组感知运算符也-eq总是输出一个数组。
由于您的数组元素全部为$null并且您与 进行比较$null,因此您的比较是有效的无操作- 例如,@( $null ) -eq $null结果@( $null )- 并且您的条件等效于:
[bool] @( $null, $null ) # -> $true - array with 2+ elements is always $True
[bool] @( $null ) # -> $false(!) - treated like: [bool] $null
Run Code Online (Sandbox Code Playgroud)
或许令人惊讶的所述隐式布尔逻辑应用于流水线逻辑到一个数组:
也就是说,一个单元素数组被(概念上)解包,其元素被解释为布尔值。
因此,[bool] @( $null )被视为与 相同[bool] $null,即$false。
通常,@( <one-and-only-element> )(或, <one-and-only-element>) 的处理方式与<one-and-only-element>布尔上下文中的处理方式相同。
相比之下,如果一个数组有2 个或更多元素,它总是 $true在一个布尔上下文中,即使它的所有元素都将被单独考虑$false。
测试任意数组是否为空的解决方法:
根据您的.Count财产条件:
if ( (<array>).Count ) { $true } else { $false }
Run Code Online (Sandbox Code Playgroud)
您可以 append -gt 0,但这不是绝对必要的,因为任何非零值都是隐式的$true。
应用于您的示例:
PS> if ( ( @($null) -eq $null ).Count ) { $true } else { $false }
True
Run Code Online (Sandbox Code Playgroud)
测试任意值作为 a (scalar) $null:
if ($null -eq <value>) { $true } else { $false }
Run Code Online (Sandbox Code Playgroud)
注意how$null必须用作LHS以防止数组过滤逻辑生效,应该<value>是一个数组。
这也是为什么如果您编写类似$var -eq $null.
[1] To-Boolean 转换总结:
以下是隐含的$false:
''/ ""(空字符串)
0 (任何数字类型)。
$null
陷阱:比较$null为布尔明确有-eq是始终$false,即使$null作为RHS(尽管通常RHS越来越强制为LHS的类型):
$false -eq $null # !! $false - unlike `$false -eq [bool] $null`
Run Code Online (Sandbox Code Playgroud)
陷阱:任何非空字符串的计算结果为$true
例如,[bool] 'False'是$true
请注意,这与显式字符串解析不同:[bool]::Parse('false')确实返回$false(和$truefor 'true',但不识别其他任何内容)。
任何其他(非集合)类型的实例都是隐式的$true,包括类型[pscustomobject]和[hashtable](PowerShell 将其视为单个对象,而不是条目的集合)。
IList接口的类集合类型- 请参阅源代码):
空集合总是$false,由于是特殊的“空集”值指示不存在从命令输出的,[System.Management.Automation.Internal.AutomationNull]::Value。
陷阱:单元素集合评估为:
$true如果它至少有 1 个元素(无论该元素是什么)。2+ 元素集合总是$true.
以下项目评估为$false:
@()
0
$null
$false
''
Run Code Online (Sandbox Code Playgroud)
在你的第一个例子中:
@($null, $null) -eq $null
Run Code Online (Sandbox Code Playgroud)
这计算出$null, $null哪个是非零集合,所以它是$true。您可以通过以下方式观察这一点:
[bool]($null, $null)
Run Code Online (Sandbox Code Playgroud)
在第二个示例中,您观察到的是像第一种情况一样过滤数组,但返回标量(而不是数组),因为数组中只有一个项目与过滤器匹配:
@($null) -eq $null
Run Code Online (Sandbox Code Playgroud)
它的计算结果为,@($null)但 powershell 正在将其计算为布尔上下文中的标量,因此它返回$false,通过以下方式观察:
[bool]@($null)
Run Code Online (Sandbox Code Playgroud)
脚注:在 powershell v2中,过滤存在一个错误$null,导致左侧$null比较。这个错误导致if/else块被完全跳过。
| 归档时间: |
|
| 查看次数: |
153 次 |
| 最近记录: |