加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 18:40:47 所属栏目:百科 来源:网络整理
导读:我正在编写一个Cmdlet,需要将对象结构传递给可能包含PSObjects的API客户端.目前,这些序列化作为包含CLI XML的 JSON字符串.相反,我需要将它视为一个对象(包括PSObject.Properties中的NoteProperties作为属性,并递归地序列化它们的值). 我尝试编写自己的JsonCo
我正在编写一个Cmdlet,需要将对象结构传递给可能包含PSObjects的API客户端.目前,这些序列化作为包含CLI XML的 JSON字符串.相反,我需要将它视为一个对象(包括PSObject.Properties中的NoteProperties作为属性,并递归地序列化它们的值).

我尝试编写自己的JsonConverter但由于某种原因它只调用顶级对象,而不是嵌套的PSObjects:

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,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,JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

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

笔记:

>在WriteJson中,将传入的对象值序列化为每个属性的值.当然你的意思是prop.Value.
>当传入的对象类型是PSObject类型时,仅从CanConvert()返回true,可以避免在WriteJson()中为非PSObject类型实现默认序列化.
>当您调用JToken.FromObject(value)时,您没有使用传入的JsonSerializer序列化程序.因此,任何JsonSerializerSettings(包括转换器)都将丢失.从理论上讲,您可以使用JToken.FromObject(Object,JsonSerializer)来保留设置,但如果您这样做,则会遇到JSON.Net throws StackOverflowException when using [JsonConvert()]中描述的错误.幸运的是,由于我们现在在需要默认序列化时从CanConvert返回false,因此不再需要.
>无需构造中间JObject.您可以直接写入JsonWriter,这将更有效.

更新:此外,我正在使用CamelCasePropertyNamesContractResolver序列化到驼峰案例.有没有办法让转换器尊重?

为类型引入custom JsonConverter后,您需要手动完成所有操作,包括重新映射属性名称.这是WriteJson()的一个版本,使用DefaultContractResolver.NamingStrategy来处理这个问题:

public override void WriteJson(JsonWriter writer,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中引入的,因此如果您使用的是早期版本,则需要创建自己的驼峰案例名称映射器,如this answer中所示.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读