对Json结果的意外转换?答:它的默认深度为2

对Json结果的意外转换?答:它的默认深度为2,json,powershell,depth,convertto-json,Json,Powershell,Depth,Convertto Json,为什么我会得到意外的结果,为什么我会得到像System.Collections.Hashtable这样的值,和/或为什么往返($Json | ConvertFrom Json | ConvertTo Json)失败 元问题 Stackoverflow有一个很好的机制来防止重复的问题,但据我所知,没有机制来防止重复的原因。以这个问题为例:几乎每周都会有一个新问题出现,原因相同,但通常很难将其定义为重复问题,因为问题本身只是略有不同。 尽管如此,如果这个问题/答案本身以重复(或离题)告终,我也不会感

为什么我会得到意外的结果,为什么我会得到像
System.Collections.Hashtable
这样的值,和/或为什么往返(
$Json | ConvertFrom Json | ConvertTo Json
)失败

元问题 Stackoverflow有一个很好的机制来防止重复的问题,但据我所知,没有机制来防止重复的原因。以这个问题为例:几乎每周都会有一个新问题出现,原因相同,但通常很难将其定义为重复问题,因为问题本身只是略有不同。 尽管如此,如果这个问题/答案本身以重复(或离题)告终,我也不会感到惊讶,但不幸的是,stackoverflow无法阻止其他程序员继续编写由这个“已知”陷阱引起的问题

复制品 几个具有相同共同原因的类似问题示例:

  • (昨天)
不同的 那么,这个“自我回答”的问题与上述重复的问题有什么不同吗?
它在标题中有共同的原因,因此它可以更好地防止由于相同原因而重复提问。

答案 具有
-Depth
参数:

指定包含的对象的多少级别包含在 JSON表示。
默认值为2

例子 要使用JSON文件执行完整的往返,您需要增加
ConvertTo-JSON
cmdlet的
-Depth

$Json | ConvertFrom-Json | ConvertTo-Json -Depth 9
TL;博士 可能是因为
ConvertTo Json
使用(.Net)完整类型名称终止比默认
-Depth
2)更深的分支,程序员假定存在错误或cmdlet限制,并且不阅读帮助或相关内容。
就我个人而言,我认为在截断分支末尾有一个简单的字符串(三点:…)会有更清晰的含义(另请参见:Github问题:)

为什么? 这个问题通常也会在另一个讨论中结束:为什么深度有限?

有些对象具有循环引用,这意味着子对象可能引用父对象(或其祖父母之一),如果将其序列化为JSON,则会导致不定式循环

以以下哈希表为例,该哈希表具有引用对象本身的
父属性

$Test = @{Guid = New-Guid}
$Test.Parent = $Test
如果执行:
$Test | converttojson
,默认情况下,它将在深度级别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"
                              }
               }
}
这就是为什么自动将
-深度设置为较大值不是一个好主意。

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


您的问题很有帮助,并且清楚地说明了当前默认的
converttojson
行为有多麻烦

至于行为的正当性:

虽然
-Depth
有助于有意截断不需要其全部深度的输入对象树,
-Depth
默认为
2
并悄悄地截断输出,从毫无戒心的用户的角度来看,相当于悄悄地实际失败序列化
-失败可能要到以后才能发现

对于大多数用户来说,这种看似随意而安静的截断是令人惊讶的,在每次调用
转换为Json
时都要考虑到这一点是不必要的负担。

我创建了一个包含更改当前行为的建议的项目,具体如下所示:

  • 忽略
    -Depth
    对象图(概念上是DTO(数据传输对象,“属性包”)的层次结构,例如从
    Convert*from*-Json
    )返回的对象图。

    • 相比之下,对任意.NET类型设置自动深度限制是有意义的,因为它们可能是深度过大的对象图,甚至可能包含循环引用;e、 例如,
      Get-ChildItem | ConvertTo-Json
      可以快速获得,深度
      -Depth
      值低至
      4
      。也就是说,使用任意.NET类型进行JSON序列化通常是不明智的:JSON不是为给定平台类型设计的通用序列化格式;相反,它关注的是DTO,只包含属性,数据类型集有限

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

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

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


尽管如此,由于JSON中不支持循环依赖关系,编写不支持循环依赖关系的序列化程序似乎比只支持一定深度的序列化程序更自然。除PowerShell中的JSON序列化程序外,所有主要的JSON序列化程序都会执行此操作。我称之为“糟糕的设计决策”,而不是“必要性”。Powershell 7.1将给出警告。“如果ConvertToJSON超过-Depth值(#13692),则发出警告”我也有同样的问题。我不禁要问,到底是什么