簡體   English   中英

如何使用JSON.NET在C#中序列化PSObject?

[英]How can I serialise PSObjects in C# with JSON.NET?

我正在編寫一個Cmdlet,需要將對象結構傳遞給可能包含PSObject的API客戶端。 目前,這些序列化作為包含CLIXML的JSON字符串。 相反,我需要將它視為一個對象(包括PSObject.Properties的NoteProperties作為屬性,並遞歸地序列化它們的值)。

我嘗試編寫自己的JsonConverter但由於某種原因它只調用頂層對象,而不是嵌套的PSObject

public class PSObjectJsonConverter : JsonConverter {

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
        if (value is PSObject) {
            JObject obj = new JObject();
            foreach (var prop in ((PSObject)value).Properties) {
                obj.Add(new JProperty(prop.Name, value));
            }
            obj.WriteTo(writer);
        } else {
            JToken token = JToken.FromObject(value);
            token.WriteTo(writer);
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
        throw new NotImplementedException();
    }

    public override bool CanRead {
        get { return false; }
    }

    public override bool CanConvert(Type objectType) {
        return true;
    }
}

此外,我正在使用CamelCasePropertyNamesContractResolver序列化到駝峰案例。 有沒有辦法讓轉換器尊重?

以下轉換器應正確序列化PSObject類型的遞歸嵌套對象:

public class PSObjectJsonConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(PSObject).IsAssignableFrom(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var psObj = (PSObject)value;
        writer.WriteStartObject();
        foreach (var prop in psObj.Properties)
        {
            //Probably we shouldn't try to serialize a property that can't be read.
            //https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.pspropertyinfo.isgettable?view=powershellsdk-1.1.0#System_Management_Automation_PSPropertyInfo_IsGettable
            if (!prop.IsGettable)
                continue;           
            writer.WritePropertyName(prop.Name);
            serializer.Serialize(writer, prop.Value);
        }
        writer.WriteEndObject();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanRead { get { return false; } }
}

筆記:

  • WriteJson您將傳入的對象value序列化為每個屬性的值。 當然你的意思是prop.Value

  • 通過僅在傳入對象類型為PSObject類型時從CanConvert()返回true ,可以避免在WriteJson()為非PSObject類型實現默認序列化。

  • 當您調用JToken.FromObject(value)您沒有使用傳入的JsonSerializer serializer 因此,任何JsonSerializerSettings (包括轉換器)都將丟失。 理論上你可以使用JToken.FromObject(Object, JsonSerializer)來保存設置,但是如果你這樣做,你會遇到JSON.Net中描述的bug在使用[JsonConvert()]時拋出StackOverflowException 幸運的是,由於我們現在在需要默認序列化時從CanConvert返回false ,因此不再需CanConvert

  • 不需要構造中間JObject 您可以直接寫入JsonWriter ,這將更有效。

更新此外,我正在使用CamelCasePropertyNamesContractResolver序列化到駝峰案例。 有沒有辦法讓轉換器尊重?

為類型引入自定義JsonConverter ,您需要手動執行所有操作,包括重新映射屬性名稱。 這是WriteJson()的一個版本,它通過使用DefaultContractResolver.NamingStrategy來處理這個問題:

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var psObj = (PSObject)value;
        writer.WriteStartObject();
        var resolver = serializer.ContractResolver as DefaultContractResolver;
        var strategy = (resolver == null ? null : resolver.NamingStrategy) ?? new DefaultNamingStrategy();

        foreach (var prop in psObj.Properties)
        {
            //Probably we shouldn't try to serialize a property that can't be read.
            //https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.pspropertyinfo.isgettable?view=powershellsdk-1.1.0#System_Management_Automation_PSPropertyInfo_IsGettable
            if (!prop.IsGettable)
                continue;
            writer.WritePropertyName(strategy.GetPropertyName(prop.Name, false));
            serializer.Serialize(writer, prop.Value);
        }
        writer.WriteEndObject();
    }

請注意,命名策略是在Json.NET 9.0.1中引入的,因此如果您使用的是早期版本,則需要創建自己的駝峰案例名稱映射器,如本答案中所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM