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

k2fxgqgv  于 2023-03-09  发布在  其他
关注(0)|答案(2)|浏览(89)

为什么会得到意外的ConvertTo-Json结果,为什么会得到类似System.Collections.Hashtable的值和/或为什么往返($Json | ConvertFrom-Json | ConvertTo-Json)失败?

meta问题

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

重复

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

与众不同

那么,这个“自我回答”的问题与上面的重复问题有什么不同呢?
它在标题中有共同的原因,这样可以更好地防止由于同一原因而重复问题。

ewm0tg9j

ewm0tg9j1#

答案

ConvertTo-Json有一个**-Depth**参数:
指定JSON表示中包含的对象的级别数。

默认值为2

示例

要对JSON文件执行完整的往返操作,您需要为ConvertTo-Json cmdlet增加-Depth

$Json | ConvertFrom-Json | ConvertTo-Json -Depth 9

靶区;DR

可能是因为ConvertTo-Json使用(.Net)完整类型名称终止比默认-Depth2)更深的分支,程序员假定存在错误或cmdlet限制,而不阅读帮助或about。
我个人认为,一个字符串如果包含一个简单的ellipsis(三个点:...)在年底切断分支,将有一个更明确的含义(另见:Github问题:8381
为什么?
这个问题通常也会在另一个讨论中结束:为什么要限制深度?
有些对象有循环引用,这意味着子对象可以引用父对象(或其祖对象之一),如果将其序列化为JSON,则会导致无限循环。
以下面的哈希表为例,该哈希表具有引用对象本身的parent属性:

$Test = @{Guid = New-Guid}
$Test.Parent = $Test

如果执行:$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"
                              }
               }
}

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

u4dcyp6a

u4dcyp6a2#

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

您的问题和answer清楚地说明了当前默认ConvertTo-Json行为的棘手问题。

*至于行为的 * 正当理由

虽然-Depth可以用于 * 有意 * 截断您不需要其完整深度的输入对象树,但**-Depth * 默认 * 为2并 * 悄悄地截断 * 输出,从不知情的用户的Angular 来看,相当于序列化的 * 悄悄的事实上的失败**-可能要到以后才能发现的失败。

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

我创建了GitHub issue #8393,其中包含一个*建议 * 来改变当前行为,具体如下

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

  • 相比之下,对 * 任意.NET类型*进行自动深度限制**确实 * 有意义,因为它们可能是深度过大的对象图,甚至可能包含循环引用;例如,Get-ChildItem | ConvertTo-Json可能很快失控,而-Depth的值低至4。也就是说,在JSON序列化中使用任意的.NET类型通常是不明智的:JSON并不是为给定平台类型设计的通用序列化格式;相反,它集中在DTO上,仅包含 * 属性 *,具有 * 有限的数据类型集 *。
  • 注意嵌套的 * 集合 ,包括哈希表,本身不受深度限制,只有它们的(标量) 元素 * 受深度限制。
    ***DTO和其他类型之间的这种区别实际上是由PowerShell本身在 * 幕后 * 使用的,即在 * 远程处理 * 和 * 后台作业***的序列化上下文中。
  • 然后,只需要使用-Depth来 * 有意地 * 在指定深度截断输入对象树(或者,大多数情况下假设,为了序列化到比内部最大深度限制100更深的级别)。

相关问题