Search code examples
c#jsonjson.net

json.net: serialise base class members first


I'm using json.net to store a serialised object that I would like people to be able to edit in a text editor. I have a base class that contains the name of the object and then a class that inherits from that and adds some other properties.

The problem is that the the properties are written out such that the derived classes properties are written first, and then the base class afetr, so I get:

{
  "MySpecialFiled": 4,
  "Name": "This Is My Object",
  "AnotherBaseField": 8,
}

rather than:

{
  "Name": "This Is My Object",
  "AnotherBaseField": 8,
  "MySpecialFiled": 4,
}

You can see how this get's a bit of a pain when you have a bunch of fields in the derived class and want to actually view/edit in a text editor!

I've messed around with the source code particularly:

public static IEnumerable<FieldInfo> GetFields(Type targetType, BindingFlags bindingAttr)

and

public static IEnumerable<PropertyInfo> GetProperties(Type targetType, BindingFlags bindingAttr)

in ReflectionUtils.cs, to try and reverse the order so that base class properties come first, but I've not had any success yet. Am I missing something trivial?


Solution

  • Answer of @sinelaw does not work because property Order returns null unless you set up your properties with [JsonProperty(Order = <someInteger>)] which kinds of defeat the purpose of using a custom sort instead of using JsonProperty attributes.

    I have modified its CustomPropertySortContractResolver to use default properties order when this order is not found.

    public class CustomPropertySortContractResolver : DefaultContractResolver
    {
        private const int MaxPropertiesPerContract = 1000;
    
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var members = GetSerializableMembers(type);
            if (members == null)
            {
                throw new JsonSerializationException("Null collection of serializable members returned.");
            }
    
            var propList = members
                .Select(member => CreateProperty(member, memberSerialization))
                .Where(x => x != null);
    
            var ind = 0;
            var orderedPropList = propList
                .OrderBy(p => ((p.Order != null ? p.Order : ind++) + (MaxPropertiesPerContract * GetTypeDepth(p.DeclaringType)) ?? -1))
                .ToList();
    
            return orderedPropList;
        }
    
        private static int GetTypeDepth(Type type)
        {
            int depth = 0;
            while ((type = type.BaseType) != null)
            {
                depth++;
            }
    
            return depth;
        }
    }