1

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

4

1 回答 1

0

我不了解 JSON.NET,但如果您使用JavaScriptSerializer,您可以提供自定义序列化程序,但仍使用内置解析/格式化等:

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; } }
}
于 2011-05-03T05:31:52.330 回答