意外的ConvertTo-Json结果?答:它的默认深度为2

iRo*_*Ron 10 powershell json depth convertto-json

为什么我得到意想不到的ConvertTo-Json结果?
为什么往返($Json | ConvertFrom-Json | ConvertTo-Json)失败?

元问题

Stackoverflow有一个很好的机制来防止重复的问题,但是据我所知,还没有一种机制可以防止有重复原因的问题。以这个问题为例:几乎每个星期都有一个新的原因相同的问题出现,但是通常很难将其定义为重复问题,因为问题本身只是稍有不同。不过,如果这个问题/答案本身最终以重复(或题外话)结尾,我不会感到惊讶,但是不幸的是stackoverflow无法写一篇文章来防止其他程序员继续写这个“已知”陷阱引起的问题。

重复项

具有相同共同原因的类似问题的一些示例:

不同

那么,这个“自我回答”的问题是否与上述重复的问题有所不同?
它具有标题中的常见原因,因此可以更好地防止由于相同原因而重复问题。

mkl*_*nt0 10

更新PowerShell 7.1在发生截断时引入了警告。虽然这比之前的安静截断要好,但下面建议的解决方案对我来说似乎更可取。


您有用的问题和答案清楚地说明了当前默认ConvertTo-Json行为的痛点有多大。

至于行为的正当性

虽然-Depth可能是有用的故意截断输入对象树,其全深度你不需要,-Depth 默认2悄悄地截断产量达到安静事实上的失败从毫无防备的用户的角度来看的系列化-失败可能不被发现,直到之后。

看似随意而安静的截断令大多数用户感到惊讶,并且在每次ConvertTo-Json调用中都必须考虑到它是一种不必要的负担。

我创建了GitHub 问题 #8393,其中包含更改当前行为建议,具体如下

  • 忽略-Depth[pscustomobject]对象图(什么是概念性的DTO(数据传输对象,“属性袋”),例如从返回的层次结构Convert*From*-Json),具体地。

    • 与此相反,确实是有意义的具有用于自动深度限制任意.NET类型,因为它们可以是过大的深度的对象图和甚至可以含有循环引用; 例如,Get-ChildItem | ConvertTo-Json可以很快失控,-Depth值低至4. 也就是说,将任意 .NET 类型与 JSON 序列化一起使用通常是不明智的:JSON并非旨在成为给定平台类型的通用序列化格式;相反,它专注于 DTO,仅包含属性,具有一组有限的数据类型

    • 请注意,嵌套集合(包括哈希表)本身不受深度限制的限制,只有它们的(标量)元素

    • 实际上,PowerShell 本身在后台使用了 DTO 和其他类型之间的这种区别,即在远程处理后台作业的序列化上下文中

  • -Depth然后只需要使用 of来故意截断指定深度的输入对象树或序列化到更深的级别(如果需要,如果深度大于内部最大深度限制,100

  • 这个深度参数值得获得年度 WTF 奖。GitHub 的这个问题真是令人悲伤。人们如何争论这种行为的敏感性?这显然是错误的,他们通过警告“修复”了它。哈哈!像平常一样使用 powershell 优化边缘情况。 (3认同)

iRo*_*Ron 7

回答

ConvertTo-Json有一个-Depth参数:

指定JSON表示形式中包含多少级包含的对象。
默认值是2

做一个完整的往返不同,需要增加一个JSON文件-DepthConvertTo-Jsoncmdlet的:

$Json | ConvertFrom-Json | ConvertTo-Json -Depth 9
Run Code Online (Sandbox Code Playgroud)

TL; DR

可能是因为使用(.Net)完整类型名ConvertTo-Json终止了比默认值-Depth2)更深的分支,因此程序员假定存在bug或cmdlet限制,并且不阅读帮助或大约。
我个人认为,在切除分支的末尾带有简单省略号(三个点:…)的字符串将具有更清晰的含义(另请参见:Github问题:8381

为什么?

这个问题通常也以另一个讨论结尾:为什么深度根本没有限制?

有些对象具有循环引用,这意味着子对象可以引用父项(或其子项之一),如果将其序列化为JSON则会导致无限循环。

以下面的哈希表为例,该哈希表具有parent指向对象本身的属性:

$Test = @{Guid = New-Guid}
$Test.Parent = $Test
Run Code Online (Sandbox Code Playgroud)

如果执行:$Test | ConvertTo-Json默认情况下,它将方便地停在2深度级别:

{
    "Guid":  "a274d017-5188-4d91-b960-023c06159dcc",
    "Parent":  {
                   "Guid":  "a274d017-5188-4d91-b960-023c06159dcc",
                   "Parent":  {
                                  "Guid":  "a274d017-5188-4d91-b960-023c06159dcc",
                                  "Parent":  "System.Collections.Hashtable"
                              }
               }
}
Run Code Online (Sandbox Code Playgroud)

这就是为什么自动将其-Depth设置为大量不是一个好主意的原因。

  • 尽管由于JSON不支持循环依赖关系,所以写一个不支持循环依赖关系的序列化程序似乎比只走到一定深度的序列化程序更为自然。所有主要的JSON序列化器(PowerShell中的*除外)都可以执行此操作。我称其为“糟糕的设计决策”,而不是“必要性”。 (5认同)
  • Powershell 7.1 会发出警告。“如果 ConvertTo-Json 超过 -Depth 值,则发出警告 (#13692)” https://docs.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-71?查看=powershell-7.1 (3认同)

归档时间:

查看次数:

1343 次

最近记录:

5 年,11 月 前