.NET 的哪种 JSON 序列化程序会将项目插入列表而不是替换列表?

发布于 2024-11-04 08:24:53 字数 1042 浏览 6 评论 0原文

好的,我有这个基本的类设置...

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; } }
}

我想将其与 Newtonsoft JSON 序列化器一起使用。但是,序列化程序不会将项目插入只读属性访问器后面的现有集合中,而是尝试将一个全新的 List 分配给该属性,这当然不能,因为没有设置器。

现在我可以切换到这个...

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; }
}

但是现在列表属性不是只读的并且可以设置为空。即使我们将setter设为私有,JSON反序列化仍然可以将其设置为null。

我想要的是一种告诉序列化器“将列表中的项目插入到这个已经存在的列表中”的方法,而不是说“用你的列表完全替换我的列表”。

那么这可以完成吗,还是我必须编写自己的 JSON 序列化转换器并将其插入?

中号

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

我为君王 2024-11-11 08:24:54

我不了解 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; } }
}

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; } }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文