How to selectively exclude a property from serialization based on the parent class type

北城余情 提交于 2019-12-24 10:38:42

问题


I'm using the Newtonsoft.JSON library to serialize several objects. In some cases I don't want to serialize a property so I've used the ShouldSerialize prefix which has been largely successful in most cases. In one case I only want to serialize a property if it belongs to a specific class.

I've tried using the stack trace but it only tells me that the JSON object is calling the ShouldSerialize method. I don't need to know what calls ShouldSerialize, I need to know what parent class ShouldSerialize belongs to such as Parent.Child.ShouldSerialize.

How can I determine what the parent class name is while using the JSON object using the code sample below?

class Foo
{
    public SharedClass SomeProperty
    {
           get;
           set;
    }
}

class Bar
{
    public SharedClass SomeProperty
    {
           get;
           set;
    }
}

class SharedClass
{
    public string SomeValue
    {
           get;
           set;
    }

    public bool ShouldSerializeSomeValue
    {
           //pseudo logic
           return ClassName == "Foo";
    }
}

回答1:


As was pointed out by Lasse Karlsen in the comments, if your SharedClass does not have a reference to its parent, there is no way for the ShouldSerializeSomeValue() method in that class to know what the parent class is.

However, if you are using Json.Net 6.0 Release 6 or later, you can work around this by using a custom JsonConverter as a means to selectively omit properties from the shared class (instead of using a ShouldSerialize() method), and then place [JsonConverter] attributes on the SharedClass properties within the appropriate parent classes to indicate which properties should be omitted for that instance.

Here is how the updated example class definitions might look. You'll notice I've marked the SharedClass instance on Foo to indicate it should use a custom converter called OmitPropertiesConverter to omit the SomeValue property. The SharedClass instance on Bar does not use a converter, so that instance will be serialized as normal.

class Foo
{
    [JsonConverter(typeof(OmitPropertiesConverter), "SomeValue")]
    public SharedClass Shared { get; set; }
}

class Bar
{
    public SharedClass Shared { get; set; }
}

class SharedClass
{
    public string SomeValue { get; set; }
    public string SomeOtherValue { get; set; }
}

Below is the code for the OmitPropertiesConverter. Its constructor accepts a propsToOmit string which is a comma-delimited list of property names to be excluded from the serialization. This gets split into an array for later use in the WriteJson method. The WriteJson method takes the SharedClass value, converts it to a JObject, then programmatically removes the properties which are in the propsToOmit array before writing the JObject to the JsonWriter.

class OmitPropertiesConverter : JsonConverter
{
    string[] propsToOmit;

    public OmitPropertiesConverter(string propsToOmit)
    {
        this.propsToOmit = propsToOmit.Split(new char[] {','},
                                             StringSplitOptions.RemoveEmptyEntries);
    }

    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(SharedClass));
    }

    public override void WriteJson(JsonWriter writer, object value, 
                                   JsonSerializer serializer)
    {
        JObject jo = JObject.FromObject(value, serializer);

        // Note: ToList() is needed here to prevent "collection was modified" error
        foreach (JProperty prop in jo.Properties()
                                     .Where(p => propsToOmit.Contains(p.Name))
                                     .ToList())
        {
            prop.Remove();
        }

        jo.WriteTo(writer);
    }

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

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

Here is a simple demo program which shows the converter in action:

class Program
{
    static void Main(string[] args)
    {
        var root = new
        {
            Foo = new Foo
            {
                Shared = new SharedClass
                {
                    SomeValue = "foo1",
                    SomeOtherValue = "foo2"
                }
            },
            Bar = new Bar
            {
                Shared = new SharedClass
                {
                    SomeValue = "bar1",
                    SomeOtherValue = "bar2"
                }
            }
        };

        string json = JsonConvert.SerializeObject(root, Formatting.Indented);
        Console.WriteLine(json);
    }
}

And here is the output of the above demo. You'll notice that the SomeValue property on the SharedClass instance inside Foo is not included in the output, but it is included on the instance inside Bar.

{
  "Foo": {
    "Shared": {
      "SomeOtherValue": "foo2"
    }
  },
  "Bar": {
    "Shared": {
      "SomeValue": "bar1",
      "SomeOtherValue": "bar2"
    }
  }
}


来源:https://stackoverflow.com/questions/27821660/how-to-selectively-exclude-a-property-from-serialization-based-on-the-parent-cla

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!