10

I have a class like this:

public class Foo
{
    public int Bar { get; set;}
}

This class is used to be stored in a NoSQL database so I need to store the Bar value. However, I don't want to expose this value through my API. So I created a class that inherits from Foo that I will return from my API.

I created the method ShouldSerializeBar by following the documentation I found here.

public class Foo2 : Foo
{
    public bool ShouldSerializeBar()
    {
        return false;
    }
}

However, the method is not called. Is there a workaround for this or another way to achieve this?

Charles Ouellet
  • 6,338
  • 3
  • 41
  • 57
  • Excluding your requirement, did you try it just on `Foo` and did it work? – Mark C. Feb 07 '17 at 20:30
  • Yeah should have mentioned it, it worked when serializing `Foo` directly. – Charles Ouellet Feb 07 '17 at 20:31
  • 1
    The reason this doesn't work is because it looks for the method on the declaring type (aka `Foo`), and not any parent/base classes. I don't see another way around it other than the below answers. – Mark C. Feb 07 '17 at 21:32

2 Answers2

10
public class Foo
{
    public int Bar { get; set;}

    public virtual bool ShouldSerializeBar()
    {
        return true;
    }
}

public class Foo2 : Foo
{
    public override bool ShouldSerializeBar()
    {
        return false;
    }
}
dana
  • 17,267
  • 6
  • 64
  • 88
  • 3
    That's what I ended up doing. It works but I wanted to avoid adding this method in my base class. Anyway, it will do the trick for now ;) – Charles Ouellet Feb 07 '17 at 20:40
6

You don't need to inherit from Foo if you use a IContractResolver.

From the docs

ShouldSerialize can also be set using an IContractResolver. Conditionally serializing a property using an IContractResolver is useful if you don't want to place a ShouldSerialize method on a class or you didn't declare the class and are unable to.

In your case something like this should work.

public class ShouldSerializeContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        JsonProperty property = base.CreateProperty(member, memberSerialization);

        if (property.DeclaringType == typeof(Foo) && property.PropertyName == "Bar")
        {
            property.ShouldSerialize = instance => false;
        }

        return property;
    }
}

And then you can use it like

var foo = new Foo();
foo.Bar = 1;

string json = JsonConvert.SerializeObject(foo,
        Formatting.Indented,
        new JsonSerializerSettings { ContractResolver = new ShouldSerializeContractResolver() });

Though I don't know if this is more intrusive than the new class (Foo2) and the virtual method in its base, at least is another option ;)

Juan M. Elosegui
  • 6,471
  • 5
  • 35
  • 48