What JSON serializer for .NET will insert items into a list rather than replacing the list?
Ok, so I have this basic class setup...
public class Location
{
public string Name{ get; set; }
private LocationList _LocationList = new LocationList();
public LocationList Locations{ get{ return _LocationList; } }
}
开发者_开发知识库public class LocationList : List<Location>{}
public class ViewModel
{
private LocationList _LocationList = new LocationList();
public LocationList Locations{ get{ return _LocationList; } }
}
which I want to use with the Newtonsoft JSON serializer. However, the serializer doesn't insert the items into the existing collection behind the read-only property accessor, but rather tries to assign an entirely new List to the property, which of course it can't since there isn't a setter.
Now I could just switch to this...
public class Location
{
public string Name{ get; set; }
public LocationList Locations{ get; set; }
}
public class LocationList : List<Location>{}
public class ViewModel
{
public LocationList RootLocations{ get; set; }
}
But now the list property isn't read-only and can be set to null. Even if we make the setter private, JSON deserialization can still set it to null.
What I want is a way to tell the serializer 'Take the items you have in your list and insert them into this already-existing list' rather than saying 'Replace my list with yours altogether'.
So can this be done, or am I going to have to write my own JSON serialization converter and plug that in?
M
I don't know about JSON.NET, but if you use JavaScriptSerializer
you can provide a custom serializer, but still use the inbuilt parsing / formatting etc:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
class Program
{
static void Main(string[] args)
{
JavaScriptSerializer ser = new JavaScriptSerializer();
ser.RegisterConverters(new[] { new ViewModelConverter() });
var model = new ViewModel { Locations = { new Location { Name = "abc",
Locations = { new Location { Name = "def"}}} } };
var json = ser.Serialize(model);
var clone = (ViewModel)ser.Deserialize(json, typeof(ViewModel));
}
}
public class ViewModelConverter : JavaScriptConverter
{
public override IEnumerable<Type> SupportedTypes
{
get { return new[] { typeof(Location), typeof(ViewModel) }; }
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
if (obj is ViewModel)
{
return new Dictionary<string, object> { { "locations", ((ViewModel)obj).Locations } };
}
if (obj is Location)
{
return new Dictionary<string, object> {
{"name", ((Location)obj).Name},
{ "locations", ((Location)obj).Locations }
};
}
throw new NotSupportedException();
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
if (type == typeof(ViewModel))
{
var model = new ViewModel();
ReadLocations(model.Locations, dictionary, serializer);
return model;
}
if (type == typeof(Location))
{
var loc = new Location();
if (dictionary.ContainsKey("name"))
{
loc.Name = (string)dictionary["name"];
}
ReadLocations(loc.Locations, dictionary, serializer);
return loc;
}
throw new NotSupportedException();
}
static void ReadLocations(LocationList locations, IDictionary<string, object> dictionary, JavaScriptSerializer serializer)
{
if (dictionary.ContainsKey("locations"))
{
foreach (object item in (IList)dictionary["locations"])
{
locations.Add((Location)serializer.ConvertToType<Location>(item));
}
}
}
}
public class Location
{
public string Name { get; set; }
private LocationList _LocationList = new LocationList();
public LocationList Locations { get { return _LocationList; } }
}
public class LocationList : List<Location> { }
public class ViewModel
{
private LocationList _LocationList = new LocationList();
public LocationList Locations { get { return _LocationList; } }
}
精彩评论