Is there any way to JSON.NET-serialize a subclass of List that also has extra properties?

前端 未结 3 1969
没有蜡笔的小新
没有蜡笔的小新 2020-12-17 19:26

Ok, we\'re using Newtonsoft\'s JSON.NET product, which I really love. However, I have a simple class structure for hierarchical locations that look roughly like this...

相关标签:
3条回答
  • 2020-12-17 19:59

    Ok... so here's what I've come up with. I had to write my own JsonConverter. I basically use it to create an inline JObject that has the properties structured as I wanted them to persist, then I persist that. I then do the reverse when I read it back out.

    However, the down'side is it doesn't use reflection or any other such things so this only works for this specific type which I had to hand-code property by property (in this case there are only two so that's good!) and it also doesn't take advantage of the DefaultValues processing which I have to re-emulate manually, meaning the attributes are basically ignored unless I reflect upon them. Still, this works. Perfect? No, but hey... things rarely are!

    Of course, comments are welcome and encouraged!

    public class LocationListJsonConverter : JsonConverter
    {
        public override bool CanConvert(System.Type objectType)
        {
            return objectType == typeof(LocationList);
        }
    
        public override object ReadJson(JsonReader reader, System.Type objectType, object existingValue, JsonSerializer serializer)
        {
            var locationList = (existingValue as LocationList) ?? new LocationList();
            var jLocationList = JObject.ReadFrom(reader);
    
            locationList.IsExpanded = (bool)(jLocationList["IsExpanded"] ?? false);
    
            var jLocations = jLocationList["_Items"];
            if(jLocations != null)
            {
                foreach(var jLocation in jLocations)
                {
                    var location = serializer.Deserialize<Location>(new JTokenReader(jLocation));
                    locationList.Add(location);
                }
            }
    
            return locationList;
    
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var locationList = value as LocationList;
    
            JObject jLocationList = new JObject();
    
            if(locationList.IsExpanded)
                jLocationList.Add("IsExpanded", true);
    
            if(locationList.Count > 0)
            {
                var jLocations = new JArray();
    
                foreach(var location in locationList)
                {
                    jLocations.Add(JObject.FromObject(location, serializer));
                }
    
                jLocationList.Add("_Items", jLocations);
    
            }
    
            jLocationList.WriteTo(writer);
    
        }
    
    }
    
    0 讨论(0)
  • 2020-12-17 20:11

    I need a class named FieldGroup that also has some properties to group some Fields. I did that as this firstly.

    public class FieldGroup : List<Field>{ ... }
    

    It has the problem to serialize as the post said. So I modified the class as below. So I can handle with it the same as the class of *FieldGroup that derived from List<Field>.

    public class FieldGroup : IPrintable, IEnumerable<Field>
    {
        public PrintFormat GroupFormat { get; set; } = new PrintFormat();
        public List<Field> Fields { get; set; } = new List<Field>();
    
        public Field this[int index]
        {
            get => Fields[index];
            set => Fields[index] = value;
        }
    
        public void Add(Field field)
        {
            Fields.Add(field);
        }
        public IEnumerator<Field> GetEnumerator()
        {
            return new FieldEnumerator(Fields);
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        ...
    }
    
    0 讨论(0)
  • 2020-12-17 20:14

    Usually when I find myself fighting something like this it tells me I should consider another approach. In this case, I would recommend the following view model structure as an alternative:

    public class Location
    {
        public bool IsExpanded { get; set; }
        public string Name { get; set; }
        public List<Location> Locations { get; set; }
    }
    
    public class ViewModel
    {
        public List<Location> RootLocations { get; set; }
    }
    
    0 讨论(0)
提交回复
热议问题