代码之家  ›  专栏  ›  技术社区  ›  felixfbecker

如何在C#中序列化PSObjectJSON.NET?

  •  5
  • felixfbecker  · 技术社区  · 7 年前

    我正在编写Cmdlet,需要将对象结构传递到可能包含 PSObject s、 目前,这些字符串序列化为包含CLIXML的JSON字符串。相反,我需要将其视为对象(包括中的NoteProperties) PSObject.Properties 作为属性,并递归序列化它们的值)。

    我试着自己写 JsonConverter 但由于某些原因,它只会被调用为顶级对象,而不是嵌套对象 P对象

    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 . 有没有办法让转换器尊重这一点?

    1 回复  |  直到 7 年前
        1
  •  5
  •   dbc    7 年前

    以下转换器应正确序列化类型为的递归嵌套对象 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; } }
    }
    

    笔记:

    更新 另外,我正在使用序列化来使用 CamelCasePropertyNamesContractResolver . 有没有办法让转换器尊重这一点?

    custom 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 因此,如果您使用的是早期版本,则需要创建自己的camel case名称映射器,如中所示 this answer