我终于花时间理解为什么Visual Studio Code唠叨我把$null
放在相等比较的左侧。
在尝试这种行为时,我发现当将包含$null
元素的数组与右侧$null
的$null
数组进行比较时,包含两个或多个$null
元素的数组会发生"预期的意外行为",但对于包含单个$null
元素的数组则不然。 也就是说,如果$array
包含多个$null
元素,则if ($array -eq $null) { 'It equals $null!' }
输出It equals $null!
,但当$array
仅包含一个元素时,输出则不会。 导致这种差异的$null
元素数量是什么?
以下测试代码演示了此行为...
function TestForNull($description, $value)
{
$comparisonResult = $value -eq $null;
$ifEntered = if ($value -eq $null) {
$true;
} else {
$false;
};
Write-Host -Object $description;
Write-Host -Object "`t`$comparisonResult.GetType(): $($comparisonResult.GetType())";
Write-Host -Object "`t`$comparisonResult.Length: $($comparisonResult.Length)";
for ($i = 0; $i -lt $comparisonResult.Length; $i++)
{
$item = $comparisonResult.GetValue($i);
$itemText = if ($null -eq $item) {
'(null)';
} else {
$item.ToString();
};
Write-Host -Object "`t`$comparisonResult[$i]: $itemText";
}
Write-Host -Object "`t`$ifEntered: $ifEntered";
}
TestForNull '0-element array' @();
TestForNull '1-element array with all $nulls' @($null);
TestForNull '2-element array with all $nulls' @($null, $null);
TestForNull '3-element array with all $nulls' @($null, $null, $null);
TestForNull '3-element array with one leading $null' @($null, 2, 3);
TestForNull '3-element array with one inner $null' @(1, $null, 3);
TestForNull '3-element array with one trailing $null' @(1, 2, $null);
TestForNull '3-element array with two leading $nulls' @($null, $null, 3);
TestForNull '3-element array with two boundary $nulls' @($null, 2, $null);
TestForNull '3-element array with two trailing $nulls' @(1, $null, $null);
。和输出...
0-element array
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 0
$ifEntered: False
1-element array with all $nulls
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 1
$comparisonResult[0]: (null)
$ifEntered: False
2-element array with all $nulls
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 2
$comparisonResult[0]: (null)
$comparisonResult[1]: (null)
$ifEntered: True
3-element array with all $nulls
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 3
$comparisonResult[0]: (null)
$comparisonResult[1]: (null)
$comparisonResult[2]: (null)
$ifEntered: True
3-element array with one leading $null
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 1
$comparisonResult[0]: (null)
$ifEntered: False
3-element array with one inner $null
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 1
$comparisonResult[0]: (null)
$ifEntered: False
3-element array with one trailing $null
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 1
$comparisonResult[0]: (null)
$ifEntered: False
3-element array with two leading $nulls
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 2
$comparisonResult[0]: (null)
$comparisonResult[1]: (null)
$ifEntered: True
3-element array with two boundary $nulls
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 2
$comparisonResult[0]: (null)
$comparisonResult[1]: (null)
$ifEntered: True
3-element array with two trailing $nulls
$comparisonResult.GetType(): System.Object[]
$comparisonResult.Length: 2
$comparisonResult[0]: (null)
$comparisonResult[1]: (null)
$ifEntered: True
我们已经(希望)知道$array -eq $null
的计算结果不是[Boolean]
,而是包含等于$null
的$array
元素的数组。 作为if
语句的条件,生成的数组必须转换为[Boolean]
,尽管我找不到任何官方的PowerShell文档详细说明了这种情况发生的细节,但正是这种转换的特殊性导致了有问题的行为。 最好的说明不是用if
语句,而是简单地用演员表达......
PS> [Boolean] @()
False
PS> [Boolean] @($null)
False
PS> [Boolean] @($null, $null)
True
PS> [Boolean] @($null, $null, $null)
True
PS> [Boolean] @(New-Object -TypeName 'Object')
True
PS> [Boolean] @((New-Object -TypeName 'Object'), (New-Object -TypeName 'Object'))
True
PS> [Boolean] @($true)
True
PS> [Boolean] @($false)
False
PS> [Boolean] @($true, $true)
True
PS> [Boolean] @($true, $false)
True
PS> [Boolean] @($false, $true)
True
PS> [Boolean] @($false, $false)
True
PS> [Boolean] @(0)
False
PS> [Boolean] @(1)
True
PS> [Boolean] @(-1)
True
PS> [Boolean] @('')
False
PS> [Boolean] @('false')
True
PS> [Boolean] @('true')
True
PS> [Boolean] @('1')
True
PS> [Boolean] @('0')
True
PS> [Boolean] @('-1')
True
如果那里没有可辨别的模式,逻辑是......
- 空数组被强制转换为
$false
。 - 具有一个元素的数组被强制转换为...
- 。该元素作为
[Boolean]
的长度(如果该元素实现IList
接口)。 - 。将该元素强制转换为
[Boolean]
(如果该元素未实现IList
接口)的结果。
- 。该元素作为
- 具有多个元素的数组被强制转换为
$true
。
因此,鉴于$array
包含一个$null
元素(例如$array = @($null)
),$array -eq $null
返回@($null)
。 将@($null)
转换为[Boolean]
时,上述规则 2 适用:$null
强制转换为$false
,因此@($null)
转换为$false
。
鉴于$array
包含多个$null
元素(例如$array = @($null, $null)
),$array -eq $null
返回一个具有相同数量(最重要的是多个)$null
元素的数组。$null
转换为$false
的事实在这里无关紧要,因为根据规则 3,此类数组总是转换为$true
。
这就是为什么数组是否包含一个或多个$null
元素很重要的原因,因为执行与$null
进行比较并将数组作为第一个操作数传递的陷阱。
延伸阅读:
IsTrue()
System.Management.Automation.LanguagePrimitives
类的方法重载- 为什么在测试 PSCustomObject 的属性时操作数的顺序很重要
- 比较运算符、集合和条件(哦, 我的!
- 将对象转换为布尔值 电源外壳
- 布尔值和 运营商
- PowerShell – 空比较 揭开神秘面纱