为什么在测试 PSCustomObject 的 属性 时操作数的顺序很重要

Why does the order of operands matter when testing for property of PSCustomObject

$psCustomObject.x -eq $null$null -eq $psCustomObject.x两种情况我都在if语句中试过了,只有后者通过了if。 为什么会这样?好像不合逻辑。

我的具体用例是一个 json 文件,其中包含多个环境的配置。环境的名称是对象中的关键,我的目标是在目标不存在的环境(可能是拼写错误)时通知用户然后停止。

我不想使用! opreator,因为它具有极高的信息代码比——它很容易被忽视,但有很大的不同,因此我一般不喜欢它。它还需要了解语言的工作原理(powershell 不是静态类型的,我不希望 reader 需要知道什么是真实的或不是真实的)。这听起来可能很愚蠢,但 powershell 不是我的主要语言,也不是我同事的主要语言。可读性是我的关键因素。

tl;dr

要将一个值与 $null-eq-ne 进行比较,始终使 $null 左轴 :

$null -eq $psCustomObject.x  # NOT $psCustomObject.x -eq $null
  • 操作数的顺序很重要,因为 PowerShell 中的比较运算符充当 过滤器array-valued LHS 值.

  • 此外,即使与 $null 以外的对象进行比较,由于隐式类型转换,操作数的顺序也可能很重要。


PowerShell 的 comparison operators, such as -eq 在设计上与 array-valued LHS 不同,因此 what操作数放在重要的地方 即使对于通常的可交换运算符
-eq-ne.

  • With a scalar LHS(单个值),比较运算符returns一个Boolean$True$False表示比较的结果。

    • 然而,即使是标量操作数放置也很重要,正如Jeff Zeitlin指出的那样,即 不同类型的操作数:通常,在比较之前,RHS操作数被强制转换为LHS的数据类型;例如,' 2 ' -eq 2 执行 字符串 比较(将整数 2 强制转换为字符串 '2'),因此 returns $False,而2 -eq ' 2 ' 执行 整数 比较(将字符串 ' 2 ' 转换为 [int]),因此 returns $True.
  • 对于数组-valued LHS(LHS values that is a collection),比较运算符returns 一个 数组 ([object[]]),因为它 作为一个 过滤器:运算符分别应用于输入数组的元素,返回的是子数组 ] 操作返回的那些元素 $True.

请注意,从 Windows PowerShell v5.1 / PowerShell Core 6.1.0 开始,PowerShell 仅支持数组值操作数作为 LHS 操作数; RHS 操作数必须是 标量 或被强制为一个。[1]


因此,在您的示例中,$null -eq $psCustomObject.x$psCustomObject.x -eq $null 不可 互换并测试不同的条件

# Is the RHS $null?
# Whether the concrete RHS value is then a scalar or an array doesn't matter.
$null -eq $psCustomObject.x

# * If $psCustomObject.x is a scalar: is that scalar $null?
# * If $psCustomObject.x is an ARRAY: 
#   RETURN THE SUB-ARRAY OF ELEMENTS THAT ARE $null
$psCustomObject.x -eq $null

在布尔上下文中使用时,例如 if 语句,数组,例如返回数组值 LHS, 计算如下:PetSerAl 致敬。

  • 数组或包含空数组1 元素数组 的计算结果为$False
  • 包含标量的 1 元素数组计算结果为该标量的(隐式)布尔值,例如,[bool] @(0) 实际上与 [=38 相同=],即 $False.
  • 包含非空数组2+元素数组1元素数组是始终 $True,无论其元素的值如何(例如,
    [bool] ($False, $False)[bool] (, (, $False)) 都是 $True

注意:array 一词在上面被随意使用。严格来说,以上内容适用于实现 [System.Collections.IList] interface - see the source code.
的任何类型的实例 除了数组之外,这还包括 [System.Collections.ArrayList][System.Collections.Generic.List[<type>]] .

等类型

示例 两个比较在布尔上下文中的计算结果不同:

注:

  • 这个例子有点做作 - 如果有更好的请告诉我们。
    可以使用运算符 -ne.

  • 提供更简单的示例
  • 我无法为您描述的具体行为举出一个示例,其中 $null -eq $psCustomObject.x returns $True,但 $psCustomObject.x -eq $null 没有't。如果这确实是您所看到的,请告诉我们所涉及的具体 .x 值。

# Construct a custom object with an array-valued .x property that
# contains at least 2 $null values.
$psCustomObject = [pscustomobject] @{ x = @(1, $null, 2, $null) }

# $False, as expected: the value of .x is an array, and therefore not $null
[bool] ($null -eq $psCustomObject.x) 

# !! $True, because because 2 elements in the input array (.x)
# !! are $null, so a 2-element array - ($null, $null) - is returned, which in a
# !! Boolean context is always $True.
[bool] ($psCustomObject.x -eq $null) 

[1] 在文档中,-replace 与比较运算符组合在一起,从技术上讲,它的 RHS 是一个数组,但该数组的元素是固有的标量操作数:要匹配的正则表达式和替换字符串。