В двух выпусках PowerShell используются разные реализации, что приводит к наблюдаемому вами различному поведению:
- Windows PowerShell uses a custom implementation, whereas PowerShell [Core] v6+, as of v7.1, uses the Json.NET library behind the scenes; see this answer for that library's rationale for deserializing to
System.Int64
([long]
) by default.
Начиная с PowerShell 7.1, существует запланированный переход на встроенную функциональность .NET JSON (доступную в .NET Core 3+), доступную через System.Text.Json
namespace, которое может восстановить сериализацию до System.Int32
([int]
) по умолчанию, учитывая, что критические изменения в любом случае неизбежны:
См. обсуждение в GitHub issue #14264 (созданный iRon на основе этого вопроса) и GitHub PR #11198, который готовит переход на System.Text.Json
.
Связанная с этим проблема заключается в том, что числа, слишком большие для размещения в System.Int64
([long]
), также сериализуются по-разному (см. GitHub issue #9207):
- Windows PowerShell: first chooses
System.Decimal
([decimal]
) and for even larger numbers System.Double
([double]
).
- PowerShell [Core] начиная с версии 7.1: всегда выбирает
System.BigInt
([bigint]
).
Кроме того, существуют различия в поддерживаемых числовых форматах:
Windows PowerShell не распознает шестнадцатеричные числа (например, 0x10
) в соответствии с Спецификация JSON[1], тогда как PowerShell [Core] версии 7.1 делает; однако, как еще одно расширение спецификации, обе поддерживают научную запись (например, 1e2
для 100
) и анализируют ее как [double]
.
Windows PowerShell, как еще одно расширение спецификации, поддерживает числа с префиксом +
(например, +10
), тогда как PowerShell [Core] версии 7.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]
s.
[1] Однако формат JSON5, предназначенный для улучшения JSON, поддерживает шестнадцатеричный формат. числа, а также другие заметные улучшения, такие как поддержка комментариев, посторонние запятые в конце и одинарные строки в кавычках.
[2] Кроме того, при использовании значений [double]
преобразование чувствительно к культуре, так что 1.2
может в некоторых культурах привести к '1.2'
(начиная с версии 7.1, что неожиданно — см. GitHub issue #14278); кроме того, большие [double]
могут заканчиваться в научной нотации, так что 1000000000000000.1
приводит к '1E+15'
. Тем не менее, использование [double]
s в качестве ключей словаря, как правило, нецелесообразно, учитывая пределы точности его преобразования из десятичного числа.
person
mklement0
schedule
27.11.2020
$x=@{One=1}
, затем$x.One.GetType()
и затем($x|ConvertTo-Json|ConvertFrom-Json).One.GetType()
. Это действительно актуальная проблема, я не думаю, что есть способ отключить это. Может быть предложение для коммита в следующем выпуске с параметром-Legacy
или-Int32
дляConvertFrom-Json
- person CFou   schedule 20.11.2020ConvertTo-Json
? - person mark   schedule 20.11.2020$a = "1" | ConvertFrom-Json; (@{ $a = 2 }).1
возвращается в2
в Windows PowerShell 5 и ничего в PowerShell Core 7.1. - person iRon   schedule 20.11.2020