61

I have the following class:

public class TriGrid
{
    private List<HexTile> _hexes;
    //other private fields...
    //other public proprerties
}

My goal is to serialize only the _hexes field, so I created the following ContractResolver:

internal class TriGridContractResolver : DefaultContractResolver
{
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        return new List<MemberInfo> { objectType.GetMember("_hexes", BindingFlags.NonPublic | BindingFlags.Instance)[0] };
    }
}

and when I want to serialize an instance of TriGrid I do:

var settings = new JsonSerializerSettings()
{
    ContractResolver = new TriGridContractResolver()
};
var json = JsonConvert.SerializeObject(someTriGrid, settings);
string strintJson = json.ToString();

but when I check the value of strintJson is always "{}". The _hexes has elements, it is not empty. If I serialize one particular HexTile it works as expected. What I am doing wrong here?

ns16
  • 1,322
  • 2
  • 17
  • 26
Bsa0
  • 2,631
  • 5
  • 17
  • 23
  • See there http://stackoverflow.com/questions/10189471/json-net-serialize-private-members-and-not-readonly-properties http://stackoverflow.com/questions/24106986/json-net-force-serialization-of-all-private-fields-and-all-fields-in-sub-classe – Ilya Aug 14 '15 at 11:32
  • 1
    @Ilya the answer to your first SO link, by to looks of it, serializes all the private fields, I just want to serialize one field in particular, the answer to the your second SO link uses CreateProperties, but what I to want serialize is a field, not a property. – Bsa0 Aug 14 '15 at 11:58

2 Answers2

128

There is no need to implement a custom DefaultContractResolver. The solution is to put [JsonProperty] on _hexes and [JsonIgnore] on all the other properties and fields.

Bsa0
  • 2,631
  • 5
  • 17
  • 23
  • 41
    Also use [`[JsonObject(MemberSerialization.OptIn)]`](http://www.newtonsoft.com/json/help/html/JsonObjectAttributeOptIn.htm) on the class. That way the `[JsonIgnore]` attributes become unnecessary. – dbc Aug 14 '15 at 14:45
  • 1
    This should be the answer for all the other questions on this topic that do the custom implementation. Just JsonProperty and JsonIgnore is a much better solution. – DFTR Sep 21 '16 at 18:11
11

Because business models will eventually change, I prefer implementing ISerializable and using .NET's way of creating momentos (i.e., a property bag). This works best when you need to version your objects at runtime. Anything that you don't want to serialize, don't put it in the property bag.

Especially, since JSON.Net (Newtonsoft.Json) will also honor it with its serialization and deserialization methods.

using System;
using System.Runtime.Serialization;

[Serializable]
public class Visitor : ISerializable
{
    private int Version;

    public string Name { get; private set; }

    public string IP { get; set: }

    public Visitor()
    {
        this.Version = 2;
    }

    public void ChangeName(string Name)
    {
        this.Name = Name;
    }

    //Deserialize
    protected Visitor(SerializationInfo info, StreamingContext context)
    {
        this.Version = info.GetInt32("Version");
        this.Name = info.GetString("Name");
    }

    //Serialize
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Version", this.Version);

        info.AddValue("Name", this.Name);
    }

    [OnDeserialized]
    private void OnDeserialization(StreamingContext context)
    {
        switch (this.Version)
        {
            case 1:
                //Handle versioning issues, if this
                //deserialized version is one, so that
                //it can play well once it's serialized as
                //version two.
                break;
        }
    }
}
Roy Oliver
  • 338
  • 3
  • 10