什么是Powershell中添加的string类型的ParameterizedProperty Chars属性?

5
请注意:
C:\> ''|Get-Member |? { $_.MemberType -eq 'ParameterizedProperty' }


   TypeName: System.String

Name  MemberType            Definition
----  ----------            ----------
Chars ParameterizedProperty char Chars(int index) {get;}


C:\>

这是一个非常奇怪的属性。首先,它是由PowerShell添加的,其次,它包含一个无限递归的属性:

C:\> ''.Chars


IsSettable          : False
IsGettable          : True
OverloadDefinitions : {char Chars(int index) {get;}}
TypeNameOfValue     : System.Char
MemberType          : ParameterizedProperty
Value               : char Chars(int index) {get;}
Name                : Chars
IsInstance          : True



C:\> ''.Chars.Value


IsSettable          : False
IsGettable          : True
OverloadDefinitions : {char Chars(int index) {get;}}
TypeNameOfValue     : System.Char
MemberType          : ParameterizedProperty
Value               : char Chars(int index) {get;}
Name                : Chars
IsInstance          : True



C:\> ''.Chars.GetHashCode()
56544304
C:\> ''.Chars.Value.GetHashCode()
34626228
C:\> ''.Chars.Value.Value.GetHashCode()
3756075
C:\> ''.Chars.Value.Value.Value.GetHashCode()
49108342
C:\> ''.Chars.Value.Value.Value.Value.GetHashCode()
62340979
C:\> ''.Chars.Value.Value.Value.Value.Value.GetHashCode()
24678148
C:\>

哈希码每次都不同,因此必须动态生成。

为什么要关心它?我想使用 PSGallery 中的 Newtonsoft.Json PowerShell 模块,但在桌面版 PowerShell(5.1)中运行时会出错,而在 Core(7.0.3)中则不会。问题在于,我没有一个最小化的重现案例,输入对象非常大。我收到的错误消息是:

ConvertTo-JsonNewtonsoft : Exception calling "SerializeObject" with "2" argument(s): "Self referencing loop detected for property 'Value' with type 'System.Management.Automation.PSParameterizedProperty'. Path 'environments[4].conditions.name.Chars'."

在PS Core中不存在这样的问题。

有人可以解释一下这个属性是什么,为什么我们需要它以及如何摆脱它吗?

编辑 1

我猜这是Newtonsoft.Json模块的问题。观察:

[DBG]> [pscustomobject]@{ a = 1} | ConvertTo-Json
{
  "a": 1
}
 [DBG]>  [pscustomobject]@{ a = 1} | ConvertTo-JsonNewtonsoft
{
  "CliXml": "<Objs Version=\"1.1.0.1\" xmlns=\"http://schemas.microsoft.com/powershell/2004/04\">\r\n  <Obj RefId=\"0\">\r\n    <TN RefId=\"0\">\r\n
 <T>System.Management.Automation.PSCustomObject</T>\r\n      <T>System.Object</T>\r\n    </TN>\r\n    <ToString>@{a=1}</ToString>\r\n    <Obj RefId=\"1\">\r\n      <TNRef RefId=\"0\" />\r\n      <MS>\r\n        <I32 N=\"a\">1</I32>\r\n      </MS>\r\n    </Obj>\r\n    <MS>\r\n      <I32 N=\"a\">1</I32>\r\n    </MS>\r\n  </Obj>\r\n</Objs>"
}
 [DBG]>

它无法正确解释PowerShell对象。 这使得它无法使用。


就属性而言,“hello”.Chars(0) 的值为“h”。这告诉我它正在检索指定位置的字符(作为字符,而不是字符串)。 - Mike Shepard
参数化属性本身并不是由PowerShell添加的 - 参见https://learn.microsoft.com/en-US/dotnet/api/system.string.chars。它只是PowerShell反映该属性引入循环的方式。但问题是:为什么序列化尝试反映字符串实例的属性,这实际上不应该发生?是否涉及不可见的`[psobject]`包装器? - mklement0
@mklement0 - 请查看编辑1。这个库太疯狂了。我会问另一个关于JSON和PowerShell的问题。 - mark
也许这可以帮助您:https://dev59.com/Drbna4cB1Zd3GeqPdZhd#58169326 - mklement0
从您的编辑中看,它似乎要求[psobject] == [pscustomobject]实例通过System.Runtime.Serialization.ISerializable序列化自己 - 这并不奇怪,因为PS自定义对象的动态属性在.NET意义上不是属性。您所看到的是PS自定义对象的CLIXML序列化。 - mklement0
我弄明白了。你能看一下这个链接吗?https://stackoverflow.com/questions/64189660/how-to-serialize-an-object-in-powershell-to-json-and-get-identical-result-in-ps? - mark
1个回答

1

简而言之

你真正的问题是,Newtonsoft.Json它的 PowerShell 封装模块都不支持 [pscustomobject] 实例

该库要求 [pscustomobject] 实例基于实现了 ISerializable 接口的 [pscustomobject] ([psobject]) 对自身进行序列化。

在Windows PowerShell中,这通常会失败,可能是由于捆绑的Newtonsoft.Json.dll程序集版本相当旧(截至本写作时,捆绑版本为8.0,而12.0为当前版本)并且存在一个错误。
  • 这个错误的表现是你看到的检测到属性'Value'的自引用循环...错误。
在PowerShell [Core] v6+中,随 PowerShell 一起提供的新版本的Newtonsoft.Json.dll预先弃用了旧版本,因此不会发生错误,但序列化问题变得明显:
  • 生成的JSON文本{"CliXml": "<Objs Version=\"1.1.0.1\"..}显示[pscustomobject]实例以CLIXML格式序列化,PowerShell的本机基于XML的序列化格式,尤其是PowerShell的远程功能所使用的格式。
  • 理论上可能 - 虽然非常繁琐 - 通过后处理手动反序列化这样的JSON,并将只有CliXml属性的对象替换为 [System.Management.Automation.PSSerializer] :: Deserialize()的返回值。

解决方案:

  • 如果您只是想以不受特定序列化格式限制的方式比较序列化表示形式,考虑直接使用 CLIXML,通过 Export-CliXmlImport-CliXml

  • 如果您确实想要一种 PS-版本无关的方法来序列化成 JSON,那么您必须自己编写一个 [pscustomobject]-to-ordered-hashtable 转换器,因为通过 Newtonsoft.Json 序列化有序哈希表 ([ordered] @{ ... }, System.Collections.Specialized.OrderedDictionary) 可以在 PowerShell 中正确往返 (实际上,它是由 ConvertFrom/To-JsonNewtonsoft 封装 cmdlet 使用的数据结构)。

这两种方法都在this related answer中演示。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接