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"
}
}
}