C#与JSON.NET继承的私有字段序列化



我有一个对象结构(在外部dll中):

public class Demo2 { 
    private int count;
    public Demo2() { 
        count = 2;
    }
}
public class MyDemo : Demo2  {
    private int count;
    public MyDemo() { 
        count = 3;
    }
}
public class Perform    {
    static void Main(string[] args)    {
        MyDemo d = new MyDemo();    
        String json = JsonSerializer.SerializeOnce<MyDemo>(d);
        Console.WriteLine(json);
        /* print: {count: 3} */
    }
}

我需要以下内容:" {count:3,基础:{count:2}}"。并稍后

假设您的对象结构(在外部dll中) 您仍然可以使用内部制造的自定义JsonConverter创建所需的JSON使用自定义ContractResolver在类型层次结构的每个级别的公共和私有字段列表中生成具有关联的get和设置方法的列表:

public class DeclaredFieldJsonConverter<T> : JsonConverter where T: new()
{
    const string basePropertyName = "base";
    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var jObj = JObject.Load(reader);
        existingValue = existingValue ?? new T();
        var type = existingValue.GetType();
        while (jObj != null && type != null)
        {
            var basejObj = jObj.ExtractPropertyValue(basePropertyName) as JObject;
            JsonObjectContract contract = (JsonObjectContract)DeclaredFieldContractResolver.Instance.ResolveContract(type);
            foreach (var jProperty in jObj.Properties())
            {
                var property = contract.Properties.GetClosestMatchProperty(jProperty.Name);
                if (property == null)
                    continue;
                var value = jProperty.Value.ToObject(property.PropertyType, serializer);
                property.ValueProvider.SetValue(existingValue, value);
            }
            type = type.BaseType;
            jObj = basejObj;
        }
        return existingValue;
    }
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        WriteJson(writer, value, value.GetType(), serializer);
    }
    void WriteJson(JsonWriter writer, object value, Type type, JsonSerializer serializer)
    {
        JsonObjectContract contract = (JsonObjectContract)DeclaredFieldContractResolver.Instance.ResolveContract(type);
        writer.WriteStartObject();
        foreach (var property in contract.Properties.Where(p => !p.Ignored))
        {
            writer.WritePropertyName(property.PropertyName);
            serializer.Serialize(writer, property.ValueProvider.GetValue(value));
        }
        var baseType = type.BaseType;
        if (baseType != null && baseType != typeof(object))
        {
            writer.WritePropertyName(basePropertyName);
            WriteJson(writer, value, baseType, serializer);
        }
        writer.WriteEndObject();
    }
}
public static class JsonExtensions
{
    public static JToken ExtractPropertyValue(this JObject obj, string name)
    {
        if (obj == null)
            return null;
        var property = obj.Property(name);
        if (property == null)
            return null;
        var value = property.Value;
        property.Remove();
        property.Value = null;
        return value;
    }
}
class DeclaredFieldContractResolver : DefaultContractResolver
{
    // As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
    // http://www.newtonsoft.com/json/help/html/ContractResolver.htm
    // http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
    // "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
    // See also https://stackoverflow.com/questions/33557737/does-json-net-cache-types-serialization-information
    static DeclaredFieldContractResolver instance;
    // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit
    static DeclaredFieldContractResolver() { instance = new DeclaredFieldContractResolver(); }
    public static DeclaredFieldContractResolver Instance { get { return instance; } }
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        var fields = objectType.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(f => !f.IsNotSerialized);
        return fields.Cast<MemberInfo>().ToList();
    }
    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        var contract = base.CreateObjectContract(objectType);
        contract.MemberSerialization = MemberSerialization.Fields;
        return contract;
    }
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        return base.CreateProperties(type, MemberSerialization.Fields);
    }
}

然后使用如下:

var demo = new MyDemo();
var json = JsonConvert.SerializeObject(demo, new DeclaredFieldJsonConverter<MyDemo>());

样品小提琴。

请注意,如果在类型层次结构中的任何地方都有一个名为base的字段,则重复的JSON属性名称将被编写,从而导致在供应时潜在的信息丢失。您可能需要检查并以某种方式处理它。

相关内容

  • 没有找到相关文章

最新更新