簡體   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