【问题标题】:Why does the order of operands matter when testing for property of PSCustomObject为什么在测试 PSCustomObject 的属性时操作数的顺序很重要
【发布时间】:2018-09-03 15:17:50
【问题描述】:

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

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

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

【问题讨论】:

  • 你能分享一下$psCustomObject是什么吗?即它的类型是什么,它的价值是什么?
  • 为什么不干脆做if (!($psCustomObject.x))
  • -eq 不是对称运算符,因此$a -eq $b$b -eq $a 不同。例如:$a = 1, 2, 3, 2, 1; $b = 2; $a -eq $b <# 2, 2 #>; $b -eq $a <# False #>
  • 我怀疑这与 PowerShell 的类型转换规则有某种联系——也就是说,PS 总是会尝试将右操作数强制转换为左操作数的类型,如果它们开始不同,你可能会得到奇怪的结果 - 例如" 02 " -eq 2 会出现$false,但2 -eq " 02 " 会返回$true
  • 由于 PowerShell 中使用的类型推断方法,当比较在左侧时,$null 或空字段将被转换为 false。当涉及数组时尤其如此。因此,经验法则:始终在左侧使用 $null 进行比较。

标签: powershell syntax operators


【解决方案1】:

tl;dr

要将值与$null-eq-ne 进行比较,始终将$null 设为LHS

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

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


PowerShell 的 comparison operators, such as -eq 在设计上与 array-valued LHS 的行为不同,因此 什么操作数放置在重要​​位置,即使对于通常可交换运算符
-eq-ne

  • 使用标量 LHS(单个值),比较运算符返回布尔值 (@987654335 @ 或 $False 表示比较的结果。

    • 但是,即使是标量操作数的放置也很重要,正如Jeff Zeitlin 所指出的那样,即不同类型的操作数:通常,RHS 操作数是强制的比较之前的 LHS 的数据类型;例如,' 2 ' -eq 2 执行 string 比较(将整数 2 强制转换为字符串 '2')并因此返回 $False,而 2 -eq ' 2 ' 执行 integer 比较(转换字符串 ' 2 '[int]),因此返回 $True
  • 对于 数组 值的 LHS(LHS 值是一个集合),比较运算符 返回一个 数组 em> ([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) 实际上与[bool] 0 相同,即$False
  • 2+-元素数组包含非空数组的1-元素数组总是$True,无关其元素的值(例如,
    [bool] ($False, $False)[bool] (, (, $False)) 都是 $True

注意:array 一词在上面的使用很松散。严格来说,以上内容适用于实现[System.Collections.IList] 接口的任何类型的实例 - 请参阅the source code
除了数组,这还包括 [System.Collections.ArrayList][System.Collections.Generic.List[<type>]] 等类型。


示例两个比较在布尔上下文中的不同评估:

注意:

  • 这个例子有点做作 - 如果有更好的例子,请告诉我们。
    操作员-ne 可以提供更简单的示例。

  • 我无法为您描述的特定行为举一个例子,其中$null -eq $psCustomObject.x 返回$True,但$psCustomObject.x -eq $null 没有。如果这确实是您所看到的,请告诉我们所涉及的具体 .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 是一个数组,但这个数组的元素是固有的标量操作数:要匹配的正则表达式,以及替换字符串。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-22
    • 2019-03-18
    • 1970-01-01
    • 2013-05-18
    • 1970-01-01
    • 1970-01-01
    • 2018-02-01
    相关资源
    最近更新 更多