Qual è la proprietà ParameterizedProperty Chars sul tipo di stringa aggiunto da Powershell?
Si prega di osservare:
C:\> ''|Get-Member |? { $_.MemberType -eq 'ParameterizedProperty' }
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
Chars ParameterizedProperty char Chars(int index) {get;}
C:\>
Questa è una proprietà molto strana. Prima di tutto viene aggiunto da Powershell, successivamente contiene una proprietà ricorsiva infinita:
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:\>
Il codice hash è ogni volta diverso, quindi deve essere generato dinamicamente.
Perché mi interessa? Sto cercando di utilizzare un modulo Newtonsoft.Json PowerShell da PSGallery e si blocca su questa proprietà, ma solo quando viene eseguito in Desktop PowerShell (5.1), non in Core (7.0.3). Il problema è che non ho una riproduzione minima, l'oggetto di input è abbastanza grande. L'errore che ottengo è:
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'."
Nessun problema di questo tipo esiste in PS Core.
Qualcuno può spiegarmi cos'è questa proprietà, perché ne abbiamo bisogno e come possiamo sbarazzarcene?
MODIFICA 1
Immagino sia un problema con il Newtonsoft.Jsonmodulo. Osservare:
[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]>
Non è in grado di interpretare correttamente gli oggetti PowerShell. Lo rende inutilizzabile.
Risposte
tl; dr
Il tuo vero problema è che né la Newtonsoft.Jsonlibreria né il modulo wrapper di PowerShell supportano le [pscustomobject]istanze :
La libreria chiede [pscustomobject]alle istanze di serializzarsi da sole , in base a [pscustomobject]( [psobject]) che implementa l' ISerializableinterfaccia.
In Windows PowerShell questo accade per fallire del tutto, presumibilmente a causa del fatto che la versione in bundle
Newtonsoft.Json.dlldell'assembly è piuttosto vecchia (al momento della stesura di questo documento, la versione in bundle è8.0, mentre12.0è attuale) e ha un bug- La manifestazione di questo bug è il
Self referencing loop detected for property 'Value' ...bug che hai visto.
- La manifestazione di questo bug è il
In PowerShell [Core] v6 +, la versione più recente di
Newtonsoft.Json.dllquella fornita con PowerShell stesso precede la versione obsoleta, quindi l'errore non si verifica, ma il problema di serializzazione diventa ovvio:Il
{ "CliXml": "<Objs Version=\"1.1.0.1\" .. }testo JSON risultante mostra che l'[pscustomobject]istanza è stata serializzata in formato CLIXML, il formato di serializzazione nativo basato su XML di PowerShell, utilizzato in particolare dalla funzionalità di comunicazione remota di PowerShell.È ipoteticamente possibile, sebbene molto complicato, deserializzare manualmente tale JSON post-elaborandolo e sostituendo gli oggetti con solo una
CliXmlproprietà con il valore restituito da[System.Management.Automation.PSSerializer]::Deserialize()
Soluzioni :
Se il tuo intento è semplicemente quello di confrontare le rappresentazioni serializzate in una forma indipendente dall'edizione PS, indipendentemente dal formato di serializzazione specifico , considera l'utilizzo di CLIXML direttamente, tramite
Export-CliXmleImport-CliXml.Se desideri un modo indipendente dall'edizione PS per serializzare in JSON , dovrai eseguire il roll
[pscustomobject]-up del tuo convertitore-to-order-hashtable, perché la serializzazione degli hashtable ordinati ([ordered] @{ ... }, System.Collections.Specialized.OrderedDictionary) tramite Newtonsoft.Json esegue correttamente il round trip in PowerShell (è, infatti, la struttura dati utilizzata daiConvertFrom/To-JsonNewtonsoftcmdlet wrapper).
Entrambi gli approcci sono dimostrati in questa risposta correlata .