Powershell 在那里添加的字符串类型的 ParameterizedProperty Chars 属性是什么?

mar*_*ark 5 string powershell

请注意:

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


   TypeName: System.String

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


C:\>
Run Code Online (Sandbox Code Playgroud)

这是一个非常奇怪的属性。首先它是由 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:\>
Run Code Online (Sandbox Code Playgroud)

哈希码每次都不一样,所以必须动态生成。

我为什么在乎?我正在尝试使用来自 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'."
Run Code Online (Sandbox Code Playgroud)

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]>
Run Code Online (Sandbox Code Playgroud)

它无法正确解释 powershell 对象。使其无法使用。

mkl*_*nt0 2

太长了;博士

您真正的问题是该它的 PowerShell 包装器模块都不支持实例Newtonsoft.Json[pscustomobject]

该库要求[pscustomobject]实例根据实现接口的( )来序列化自身[pscustomobject][psobject]ISerializable

  • 在 Windows PowerShell 中,这会彻底失败,可能是由于程序集的捆绑版本Newtonsoft.Json.dll相当旧(在撰写本文时,捆绑版本是8.0,而是12.0最新版本)并且存在错误

    • 这个bug的表现形式就是Self referencing loop detected for property 'Value' ...你看到的bug。
  • 在 PowerShell [Core] v6+ 中,Newtonsoft.Json.dllPowerShell 本身附带的较新版本会抢占过时的版本,因此不会发生错误,但序列化问题变得明显:

    • 生成的{ "CliXml": "<Objs Version=\"1.1.0.1\" .. }JSON 文本显示该[pscustomobject]实例以 CLIXML 格式序列化,这是 PowerShell 的本机基于 XML 的序列化格式,尤其是 PowerShell 的远程处理功能所使用的格式。

    • 假设可以通过后处理这种 JSON 并仅用具有返回值的属性替换对象来手动反序列化此类 JSON,尽管非常麻烦CliXml[System.Management.Automation.PSSerializer]::Deserialize()


解决方案

  • 如果您的目的只是比较与 PS 版本无关的形式的序列化表示,而不考虑特定的序列化格式,请考虑通过Export-CliXml和直接使用 CLIXML Import-CliXml

  • 如果您确实想要以与 PS 版本无关的方式序列化为JSON,则必须使用自己的[pscustomobject]-to-ordered-hashtable 转换器,因为通过 Newtonsoft.Json序列化有序哈希表 ( [ordered] @{ ... }, )可以在 PowerShell 中正确往返(事实上​​,它是包装器 cmdlet 使用的数据结构)。System.Collections.Specialized.OrderedDictionaryConvertFrom/To-JsonNewtonsoft

此相关答案中演示了这两种方法。