为什么当 $array -eq $null仅包含一个$null元素时$array计算结果不$true?



我终于花时间理解为什么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

如果那里没有可辨别的模式,逻辑是......

  1. 空数组被强制转换为$false
  2. 具有一个元素的数组被强制转换为...
    • 。该元素作为[Boolean]的长度(如果该元素实现IList接口)。
    • 。将该元素强制转换为[Boolean](如果该元素未实现IList接口)的结果。
  3. 具有多个元素的数组被强制转换为$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 – 空比较 揭开神秘面纱

相关内容

  • 没有找到相关文章

最新更新