简体   繁体   English

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

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

Please observe:请注意:

Windows Powershell Windows PowerShell

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

Powershell Core Powershell 核心

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

This is not benign.这不是良性的。 Consider a map with keys being integers:考虑一个键为整数的映射:

$x = @{
    123 = 1
}

The key 123 is an Int32 , not Int64 .键 123 是Int32 ,而不是Int64 So, if 123 comes from parsed JSON it would be of different types in different shells.因此,如果 123 来自解析的 JSON,它将在不同的 shell 中具有不同的类型。 Now:现在:

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

And this is true on both shells.这在两个壳上都是正确的。 This change in behavior wrecks havoc in our automation scripts that manipulate things using REST APIs.这种行为变化破坏了我们使用 REST API 操作事物的自动化脚本。

Can this behavior of Powershell Core be turned off?可以关闭 Powershell Core 的这种行为吗?

  • The two PowerShell editions use different implementations , causing the divergent behavior you observed:两个 PowerShell 版本使用不同的实现,导致您观察到的不同行为:

    • Windows PowerShell uses a custom implementation, whereas PowerShell [Core] v6+ , as of v7.1, uses the Json.NET library behind the scenes; Windows PowerShell使用自定义实现,而PowerShell [Core] v6+从 v7.1 开始,在幕后使用Json.NET 库 see this answer for that library's rationale for deserializing to System.Int64 ( [long] ) by default.请参阅此答案,了解该库默认反序列化为System.Int64 ( [long] ) 的基本原理。
  • As of PowerShell 7.1, there's a planned move to the now native .NET JSON functionality (available in .NET Core 3+) available via the System.Text.Json namespace , which may restore serializing to System.Int32 ( [int] ) by default , given that breaking changes are inevitable anyway:从 PowerShell 7.1 开始,计划通过System.Text.Json命名空间向现在的本机 .NET JSON 功能(在 .NET Core 3+ 中可用)移动,这可以通过以下方式恢复到System.Int32 ( [int] ) 的序列化default ,因为无论如何都不可避免地会发生重大更改:

    • See the discussion in GitHub issue #14264 (created by iRon based on this question) and GitHub PR #11198 , which is preparing the move to System.Text.Json .请参阅GitHub 问题 # 14264 (由iRon基于此问题创建)和GitHub PR #11198 中的讨论,该讨论正在准备迁移到System.Text.Json

    • A related problem is that numbers too large to fit into a System.Int64 ( [long] ) are also serialized differently (see GitHub issue #9207 ):一个相关的问题是,太大而无法放入System.Int64 ( [long] ) 的数字也以不同的方式序列化(请参阅GitHub 问题 #9207 ):

      • Windows PowerShell: first chooses System.Decimal ( [decimal] ) and for even larger numbers System.Double ( [double] ). Windows PowerShell:首先选择System.Decimal ( [decimal] ),对于更大的数字System.Double ( [double] )。
      • PowerShell [Core] as of v7.1: always chooses System.BigInt ( [bigint] ). PowerShell [Core] 自 v7.1 起:始终选择System.BigInt ( [bigint] )。
    • Also, there are differences with respect to the number formats supported:此外,支持的数字格式也存在差异

      • Windows PowerShell does not recognize hexadecimal numbers (eg, 0x10 ), in accordance with the JSON spec [1] , whereas PowerShell [Core] as of v7.1 does ;的Windows PowerShell不能识别十六进制数(例如, 0x10 ),根据JSON规范[1],而PowerShell的[核心]作为V7.1的确实; however, as another extension to the spec, both support scientific notation (eg, 1e2 for 100 ) and parse it as [double] .然而,作为规范的另一个扩展,两者都支持科学记数法(例如, 1e2表示100 )并将其解析为[double]

      • Windows PowerShell, as another extension to the spec, does support + -prefixed numbers (eg, +10 ), whereas PowerShell [Core] as of v7.1 does not . Windows PowerShell中,作为另一个扩展规范,支持+ -prefixed数字(例如+10 ),而PowerShell的[核心]作为V7.1的没有

      • (Also, both editions support single -quoted strings as an extension.) (此外,两个版本都支持引号字符串作为扩展名。)


Workaround :解决方法

  • Generally, note that the problem may often not surface, given PowerShell's ability to mix different numeric types and widen types on demand.通常,请注意,鉴于 PowerShell 能够混合不同的数字类型并按需扩展类型,问题通常可能不会浮出水面。

  • However, as the question shows, when numbers are used as the keys of a hashtable (dictionary) , a type-exact value must be passed for lookup in order to locate entries.但是,正如问题所示,当数字用作哈希表(字典)键时,必须传递类型精确值以进行查找以定位条目。

Therefore, the simplest workaround is to cast the hashtable key to [int] , which allows later lookups with just, say, [123] (or even .123 ):因此,最简单的解决方法是哈希表键转换[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

Another option is to use a [pscustomobject] rather than a hashtable, in which case the numeric keys implicitly become property names , which are always strings .另一种选择是使用[pscustomobject]而不是哈希表,在这种情况下,数字隐式成为属性名称,属性名称始终为字符串

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

This would work even with a numeric variable:这甚至适用于数字变量:

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

Caveat : When a key is implicitly stringified to become a property name, it is invariably a decimal representation that is used;警告:当一个键被隐式字符串化成为一个属性名称时,它总是使用十进制表示; eg, [pscustomobject] @{ [int] 0x10 = 'bingo' } results in an object whose property name is '16' .例如, [pscustomobject] @{ [int] 0x10 = 'bingo' }会生成一个属性名称为'16'的对象。 [2] [2]

However, note that hashtables / dictionaries are more lightweight than [pscustomobject] s.但是,请注意哈希表/字典比[pscustomobject]更轻量级。


[1] However, the JSON5 format, which is meant to improve on JSON, does support hex. [1] 但是,旨在改进 JSON 的JSON5格式确实支持十六进制。 numbers, along with other notable improvements, such as support for comments, extraneous trailing commas, and single -quoted strings.数字,以及其他显着改进,例如支持注释、无关的尾随逗号和引号字符串。

[2] Also, with [double] values the conversion is culture-sensitive , so that 1.2 can in some cultures result in '1.2' (as of v7.1, which is unexpected - see GitHub issue #14278 ); [2] 此外,对于[double]值,转换是文化敏感的,因此1.2在某些文化中可能会导致'1.2' (从 v7.1 开始,这是出乎意料的 - 参见GitHub 问题 #14278 ); also, large [double] s can end up in scientific notation, so that 1000000000000000.1 results in '1E+15' .此外,大[double]可以以科学记数法结束,因此1000000000000000.1结果为'1E+15' That said, using [double] s as dictionary keys is generally ill-advised, given the accuracy limits of its from-decimal-number conversion.也就是说,考虑到从十进制数转换的准确性限制,使用[double] s 作为字典键通常是不明智的。

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

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