繁体   English   中英

Powershell Core 将 JSON 中的数字反序列化为 Int64,而 Windows Powershell 将其作为 Int32

[英]Powershell Core deserializes numbers in JSON as Int64 vs Windows Powershell which does it as Int32

请注意:

Windows PowerShell

C:\> ("1" | ConvertFrom-Json).gettype().name
Int32
C:\>

Powershell 核心

C:\> ("1" | ConvertFrom-Json).gettype().name
Int64
C:\>

这不是良性的。 考虑一个键为整数的映射:

$x = @{
    123 = 1
}

键 123 是Int32 ,而不是Int64 因此,如果 123 来自解析的 JSON,它将在不同的 shell 中具有不同的类型。 现在:

C:\> $x[[Int32]123]
1
C:\> $x[[Int64]123]
C:\>

这在两个壳上都是正确的。 这种行为变化破坏了我们使用 REST API 操作事物的自动化脚本。

可以关闭 Powershell Core 的这种行为吗?

  • 两个 PowerShell 版本使用不同的实现,导致您观察到的不同行为:

    • Windows PowerShell使用自定义实现,而PowerShell [Core] v6+从 v7.1 开始,在幕后使用Json.NET 库 请参阅此答案,了解该库默认反序列化为System.Int64 ( [long] ) 的基本原理。
  • 从 PowerShell 7.1 开始,计划通过System.Text.Json命名空间向现在的本机 .NET JSON 功能(在 .NET Core 3+ 中可用)移动,这可以通过以下方式恢复到System.Int32 ( [int] ) 的序列化default ,因为无论如何都不可避免地会发生重大更改:

    • 请参阅GitHub 问题 # 14264 (由iRon基于此问题创建)和GitHub PR #11198 中的讨论,该讨论正在准备迁移到System.Text.Json

    • 一个相关的问题是,太大而无法放入System.Int64 ( [long] ) 的数字也以不同的方式序列化(请参阅GitHub 问题 #9207 ):

      • Windows PowerShell:首先选择System.Decimal ( [decimal] ),对于更大的数字System.Double ( [double] )。
      • PowerShell [Core] 自 v7.1 起:始终选择System.BigInt ( [bigint] )。
    • 此外,支持的数字格式也存在差异

      • 的Windows PowerShell不能识别十六进制数(例如, 0x10 ),根据JSON规范[1],而PowerShell的[核心]作为V7.1的确实; 然而,作为规范的另一个扩展,两者都支持科学记数法(例如, 1e2表示100 )并将其解析为[double]

      • Windows PowerShell中,作为另一个扩展规范,支持+ -prefixed数字(例如+10 ),而PowerShell的[核心]作为V7.1的没有

      • (此外,两个版本都支持引号字符串作为扩展名。)


解决方法

  • 通常,请注意,鉴于 PowerShell 能够混合不同的数字类型并按需扩展类型,问题通常可能不会浮出水面。

  • 但是,正如问题所示,当数字用作哈希表(字典)键时,必须传递类型精确值以进行查找以定位条目。

因此,最简单的解决方法是哈希表键转换[int] ,这允许稍后仅使用[123] (甚至.123 )进行查找:

# Works in both Windows PowerShell and PowerShell [Core]
# Without the [int] cast, the lookup would fail in PowerShell [Core] as of v7.1
PS> $key = '123' | ConvertFrom-Json; @{ [int] $key = 'bingo' }[123]
bingo

另一种选择是使用[pscustomobject]而不是哈希表,在这种情况下,数字隐式成为属性名称,属性名称始终为字符串

# Note the use of .123, i.e. property access.
PS> $key = '123' | ConvertFrom-Json; ([pscustomobject] @{ [int] $key = 'bingo' }).123
bingo

这甚至适用于数字变量:

$lookup=123; ([pscustomobject] @{ [int] $key = 'bingo' }).$lookup

警告:当一个键被隐式字符串化成为一个属性名称时,它总是使用十进制表示; 例如, [pscustomobject] @{ [int] 0x10 = 'bingo' }会生成一个属性名称为'16'的对象。 [2]

但是,请注意哈希表/字典比[pscustomobject]更轻量级。


[1] 但是,旨在改进 JSON 的JSON5格式确实支持十六进制。 数字,以及其他显着改进,例如支持注释、无关的尾随逗号和引号字符串。

[2] 此外,对于[double]值,转换是文化敏感的,因此1.2在某些文化中可能会导致'1.2' (从 v7.1 开始,这是出乎意料的 - 参见GitHub 问题 #14278 ); 此外,大[double]可以以科学记数法结束,因此1000000000000000.1结果为'1E+15' 也就是说,考虑到从十进制数转换的准确性限制,使用[double] s 作为字典键通常是不明智的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM