简体   繁体   中英

Newtonsoft.json or System.Text.Json Serialize only the property's defined type not inherited values

Consider you have:

class ContentRef {
  SomeProperty
}

class Content : ContentRef {
   SomeOtherProperty
}

class C  {
   ContentRef someProperty;
   List<ContentRef> someList;
}

var someObject = new C { someProperty = new Content(), someList = new List<ContentRef>({new Content()})};

By default both Newtonsoft and System.Text.Json serialize all of the properties of Content in someObject. But clearly, the definition for C says that both are of type A. I want to make sure that in both the case of the direct property A and List that the only thing that gets serialized is A's properties even if you assign B into it.

This happens all of the time in document databases when you have a Ref class for a property that you're setting and you set it to the full class that inherits from the ref class for the rest of the data. You only want the document database to store the ref class's data, not all of the full class because when it's deserialized you only care about the Ref class as defined.

I've got this:

public class StrictTypeContractResolver : DefaultContractResolver
{
    private readonly FieldInfo _IsSealedField = typeof(JsonContract).GetField("IsSealed", BindingFlags.Instance | BindingFlags.NonPublic)!;

    public override JsonContract ResolveContract(Type type)
    {
        var resolveContract = base.ResolveContract(type);
        _IsSealedField.SetValue(resolveContract, true);
        return resolveContract;
    }
}

Which works in the direct property case and only serializes the actual defined type. However, I can't figure out how to get it to work on the List type (either a hashset, IList, or IEnumerable). It serializes the entire thing instead of just the List like it should.

https://dotnetfiddle.net/CCbOFf

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using static Newtonsoft.Json.JsonConvert;

class Ref { public int a {get;set;} public string b {get;set;} public DateTime c {get;set;} }
class DerivedRef : Ref { public bool d {get;set;} public long e {get;set;} }

class Ref2 { public int a {get;set;} public string b {get;set;} public DateTime c {get;set;} }
class DerivedRef2 : Ref2 { public bool d {get;set;} public long e {get;set;} }

public class StrictTypeContractResolver<T>: DefaultContractResolver
{
    
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        if(type.IsSubclassOf(typeof(T)))
        {           
            return base.CreateProperties(typeof(T), memberSerialization);
        }
        
        return base.CreateProperties(type, memberSerialization);
    }
    
}

public class Program
{
    public static void Main()
    {       
        var list = new Ref[]{
            new Ref{a=1,b="2",c=DateTime.Now}
            ,new DerivedRef{a=1,b="2",c=DateTime.Now,d=true,e=999}
        };

        Console.WriteLine(PerformSerialization(list));
            
        var list2 = new Ref2[]{
            new Ref2{a=1,b="2",c=DateTime.Now}
            ,new DerivedRef2{a=1,b="2",c=DateTime.Now,d=true,e=999}
        };

        Console.WriteLine(PerformSerialization(list2));
    }
    
    public static string PerformSerialization<T>(IList<T> list)
    {
        var settings = new JsonSerializerSettings { ContractResolver = new StrictTypeContractResolver<T>(), Formatting = Formatting.Indented  };
        return SerializeObject(list, settings);
    }
    
    
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM