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...
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);
}
}
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();
}
...
}
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; }
}