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