应为空或 null 的浮点变量被设置为 0

float variable that should be empty or null is being set to 0

我正在开发一个接受 [Single]$DurationMS 作为可选参数的函数。这应该是浮点值。所以在我的函数中,我有以下代码来检查它是否被提供给函数。如果提供,我想将该值添加到嵌套在另一个对象中的对象。

if ($DurationMS -ne $null) {
$MyObject.attributes | Add-Member -MemberType NoteProperty -Name 'duration.ms' -Value $DurationMS
}

一切看起来都很好,除了当我测试它时,我的持续时间为 0,我不知道为什么。

duration.ms
-----------
          0

所以我的条件评估为真,但我不明白为什么。

  • [single] is a .NET value type,并且这种类型的实例 永远不会是 $null.

    • [single].IsValueType 返回 $true 告诉你它是一个值类型。
    • $null 仅适用于 .NET reference types 并告诉您这是 reference no object.
  • 因此 测试您的 [single] 类型的 $DurationMS 参数变量是 $null 毫无意义:

    • A [single] 实例的默认值为 0,因此您的 $DurationMS -ne $null 条件默认有效 0 -ne $null,即 $true
  • 在给定调用中检查参数是否传递给给定 (non-mandatory) 参数 的 可靠方法是 参考 automatic $PSBoundParameters variable, as Santiago Squarzon 建议。

    • 此变量包含一个字典,其中包含所有显式传递的参数的条目,以它们的参数名称为键(无前缀 -);例如,如果您的函数是用 -DurationMS 1.2$PSBoundParameters['DurationMS'] returns 1.2 调用的,而 $PSBoundParameters.ContainsKey('DurationMS') 表示 $true

因此:

# Was an argument passed to -DurationMS?
if ($PSBoundParameters.ContainsKey('DurationMS')) {
  $MyObject.attributes | 
    Add-Member -MemberType NoteProperty -Name 'duration.ms' -Value $DurationMS
}

以下几个方面是附带的:

  • if ($DurationMs) 仅当您还想考虑 0explicit 参数时才有效“未提供任何值”,因为 [single] 类型的 $DurationMsif ($DurationMs)if ($DurationMs -ne 0)

    相同
    • PowerShell 允许您在布尔上下文中使用 any 类型的表达式;对于 numeric 类型,0 映射到 $false,任何非零值映射到 $true.
    • 虽然这种隐式 to-Boolean 转换行为通常很方便,但它有其缺陷 - 请参阅 的底部部分以获取规则摘要。
  • 鉴于 许多 PowerShell 运算符可以作为 LHS 在 数组 (集合)上隐式操作 - 在这种情况下,它们充当 filters,返回匹配项的 子数组 - 通常最好在 LHS 上放置一个标量比较操作数(在这种情况下我们知道 non-literal 操作数根据定义也是一个标量 - 一个 [single] 实例 - 所以这无关紧要)。

    • 将标量放在 LHS 上可以避免误报/漏报,例如以下示例:

      $arr = 0, $null
      # !! -> 'null', because (0, $null) -ne $null filters the
      # !!    array to @(0), and [bool] @() - perhaps surprisingly - is $false
      if ($arr -ne $null) { 'not null' } else { 'null' }
      
      # OK, with $null on the LHS
      # -> 'not null'
      if ($null -ne $arr) { 'not null' } else { 'null' } 
      
    • 然而,即使在 LHS $null 上也会表现出意想不到的行为,即
      -lt-le-gt-ge 运算符,如 中所述;例如:

       $null -lt 0 # !! -> $true - even though [int] $null yields 0
      
    • 如果 PowerShell 为 $null 提供专门的测试,这些陷阱就可以避免;实施这样的测试 - 以 $var -is $null$var -isnull 的形式 - 是 GitHub PR #10704 的主题;不幸的是,该 PR 被其创建者放弃了,此后没有人接手这项工作,这就是为什么从 PowerShell 7.2.2 开始不存在此类测试的原因。

  • Lee Dailey points out, a property name such as duration.ms can be problematic, given that it contains ., which normally suggests a nested property access, given that an (unquoted) . serves as the member-access operator.