Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
440 views
in Technique[技术] by (71.8m points)

c# - How to serialize only inherited properties of a class using a JsonConverter

I'm trying to serialize only the inherited properties of a class using json.net. I'm aware of the [JsonIgnore] attribute, but I only want to do ignore them on certain occasion, so I used a custom JsonConverter instead.

Here's my class:

public class EverythingButBaseJsonConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Find properties of inherited class
        var classType = value.GetType();
        var classProps = classType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();

        // Remove the overrided properties
        classProps.RemoveAll(t =>
        {
            var getMethod = t.GetGetMethod(false);
            return (getMethod.GetBaseDefinition() != getMethod);
        });

        // Get json data
        var o = (JObject)JToken.FromObject(value);

        // Write only properties from inhertied class
        foreach (var p in o.Properties().Where(p => classProps.Select(t => t.Name).Contains(p.Name)))
            p.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        throw new NotImplementedException("");
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

When doing a simple o.WriteTo(writer); it give the same result as not using a converter. When iterating through properties and using WriteTo on the properties, it works fine for base type (int, string, etc), but I'm having problem with collections.

Expected:

{
  "Type": 128,
  "Time": [
    1,
    2,
  ],
  "Pattern": 1,
  "Description": ""
}

Got:

  "Type": 128,
  "Time": [
    1,
    2,
  ]"Pattern": 1,
  "Description": ""

As you can see, the collection is missing the "," and endline portion. I'm also missing the global { } for the whole object.

I am doing things the correct way? Is there an easier way to get the result I want?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Not sure why your code doesn't work (maybe a Json.NET bug?). Instead, you can remove the properties you don't want from the JObject and write the entire thing in one call:

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Find properties of inherited class
        var classType = value.GetType();
        var classProps = classType.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList();

        // Remove the overrided properties
        classProps.RemoveAll(t =>
        {
            var getMethod = t.GetGetMethod(false);
            return (getMethod.GetBaseDefinition() != getMethod);
        });

        // Get json data
        var o = (JObject)JToken.FromObject(value);

        // Remove all base properties
        foreach (var p in o.Properties().Where(p => !classProps.Select(t => t.Name).Contains(p.Name)).ToList())
            p.Remove();

        o.WriteTo(writer);
    }

Alternatively, you could create your own contract resolver and filter out base properties and members:

public class EverythingButBaseContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        if (member.ReflectedType != member.DeclaringType)
            return null;
        if (member is PropertyInfo)
        {
            var getMethod = ((PropertyInfo)member).GetGetMethod(false);
            if (getMethod.GetBaseDefinition() != getMethod)
                return null;
        }
        var property = base.CreateProperty(member, memberSerialization);
        return property;
    }
}

And then use it like:

        var settings = new JsonSerializerSettings { ContractResolver = new EverythingButBaseContractResolver() };
        var json = JsonConvert.SerializeObject(rootObject, Formatting.Indented, settings);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...