C# 使用以复杂类型为键的对象引用和字典将复杂类型序列化/反序列化为 Json

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11644905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 18:38:50  来源:igfitidea点击:

Serialize/Deserialize complex type to Json with object references and dictionaries that have complex type as key

c#jsonserializationjson.net

提问by larsbeck

I am trying to serialize/deserialize a complex type. I want object references to be preserved, meaning that if the instance of an object is referenced multiple times in the object graph, during deserialization I want the deserializer to only create that instance once and have it referenced multiple times (vs. create that object instance multiple times).

我正在尝试序列化/反序列化复杂类型。我希望保留对象引用,这意味着如果在对象图中多次引用对象的实例,在反序列化期间,我希望反序列化器仅创建该实例一次并多次引用它(与创建该对象实例相比)多次)。

The second thing I need the system to deal with is a dictionary where the key is a complex type itself.

我需要系统处理的第二件事是字典,其中键本身是复杂类型。

I was able to achieve both with the DataContractSerializer serializing to XML. However I am failing to find any Json serializer that can do this. I tried Json.NET and ServiceStack, but no luck.

我能够通过将 DataContractSerializer 序列化为 XML 来实现这两个目标。但是我没有找到任何可以做到这一点的 Json 序列化器。我尝试了 Json.NET 和 ServiceStack,但没有运气。

See the sample code below:

请参阅下面的示例代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Xml;
using Newtonsoft.Json;

namespace Serialization
{
    class Program
    {

        static void Main(string[] args)
        {
            var transportModel = CreateSampleModel();


            //Serialize with DataContractSerializer
            var serializer = new DataContractSerializer(typeof(TransportModel), null, int.MaxValue, false, true, null, null);
            string serializedObjectXml;
            using (var sw = new StringWriter())
            {
                using (var writer = new XmlTextWriter(sw))
                {
                    serializer.WriteObject(writer, transportModel);
                    writer.Flush();
                    serializedObjectXml = sw.ToString();
                }
            }

            //Deserialize with DataContractSerializer
            byte[] byteArray = Encoding.ASCII.GetBytes(serializedObjectXml);
            var stream = new MemoryStream(byteArray);
            var deserializedObjectXml = serializer.ReadObject(stream);


            //Serialize with Json.NET
            var serializedObjectJson=JsonConvert.SerializeObject(transportModel);

            //Deserialize with Json.NET - this fails because of the key in the dictionary being a complex type
            var deserializedObjectJson = JsonConvert.DeserializeObject(serializedObjectJson);
        }


        static TransportModel CreateSampleModel()
        {
            var transportModel = new TransportModel();

            // dests
            var fra = new Destination
            {
                Id = 0,
                Name = "FRA",
                Demand = 900
            };
            var det = new Destination
            {
                Id = 1,
                Name = "DET",
                Demand = 1200
            };


            var dests = new List<Destination> { fra, det};

            //origs
            var gary = new Origin
            {
                Id = 0,
                Name = "GARY",
                Supply = 1400,
                Cost = new Dictionary<Destination, int>{
                    {fra, 39},
                    {det, 14}
                }
            };


            var origs = new List<Origin> { gary};

            transportModel.Destinations = dests;
            transportModel.Origins = origs;

            return transportModel;
        }
    }

    [DataContract]
    class Destination
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Demand { get; set; }
    }

    [DataContract]
    class Origin
    {
        [DataMember]
        public int Id { get; set; }
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public int Supply { get; set; }
        [DataMember]
        public Dictionary<Destination, int> Cost { get; set; }
    }

    [DataContract]
    class TransportModel
    {
        [DataMember]
        public List<Origin> Origins;
        [DataMember]
        public List<Destination> Destinations;

        public TransportModel()
        {
            Origins = new List<Origin>();
            Destinations = new List<Destination>();
        }
    }
}

采纳答案by James Newton-King

Json.NET supports handling object references: Preserving Object References

Json.NET 支持处理对象引用:Preserving Object References

Complex type dictionary keys can be handled by creating a TypeConverterthat will convert the type to and from a string. Json.NET will use that string as the dictionary key.

复杂类型字典键可以通过创建一个TypeConverter来处理,该TypeConverter将在类型与字符串之间进行转换。Json.NET 将使用该字符串作为字典键。

回答by mythz

Use .NET's built-in BinaryFormatter, which preserves references.

使用 .NET 的内置 BinaryFormatter,它保留引用。

Although I personally would discourage the use of object graphs blobs with cyclical dependencies, which is not modifiable, introspectable and stands little chance of handling versioning changes.

虽然我个人不鼓励使用具有循环依赖关系的对象图 blob,它不可修改、内省并且几乎没有机会处理版本更改。

A Data Transfer Object (i.e. types used for serialization) should ideally be clean, self-describing and serialized in a popular, versionable and tolerant format.

理想情况下,数据传输对象(即用于序列化的类型)应该是干净的、自描述的,并以流行的、可版本化和宽容的格式进行序列化。