在维护对象引用的同时序列化 C# 对象

Posted

技术标签:

【中文标题】在维护对象引用的同时序列化 C# 对象【英文标题】:Serialize C# Objects while maintaining object references 【发布时间】:2015-07-21 19:33:53 【问题描述】:

所以我有多个自定义类,它们在它们的实例中引用其他类。我知道序列化一般是如何工作的,但是我该如何处理对象引用呢?目标是将对象保存为 xml 或二进制文件,以便以后恢复状态。

在这个简化的示例中,Person 由 id 标识,并且有一个引用的其他 Person 对象列表,称为朋友。

public class Person
      public int id;
      public List<Person> friends;


如何序列化和反序列化此示例并保持对象引用完整?此外,我认为如果试图恢复对尚未反序列化的 Person 的引用,反序列化可能会很棘手。

【问题讨论】:

您究竟是如何尝试发送和接收这些对象的? 只是在本地(到文件)以 xml 或二进制文件保存/加载它们 【参考方案1】:
[XmlRootAttribute("Person")]
public class Person
    [XmlAttribute("_id")]
    public int id;
    [XmlElement("friends")]
    public List<Person> friends;

然后使用 XmlSerializer 类创建一个 xml 文件和/或你的对象 https://msdn.microsoft.com/en-us/library/58a18dwa.aspx

【讨论】:

非常酷,我不知道_id 属性。我刚刚用我的答案中的代码对其进行了测试,“鲍勃的朋友,斯科特的朋友”返回真。 (但是我必须使我序列化的对象为Person 而不是List&lt;Person&gt;,并且我传入bob 而不是people)。【参考方案2】:

如果您搭载 WCF 并使用DataContract 属性并设置IsReference = true,则可以跟踪引用,然后您需要使用DataContractSerializer 来序列化您的数据。

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;

namespace SandboxConsole

    internal class Program
    
        public static void Main()
        
            var bob = new Person Id = 0;
            var scott = new Person Id = 1;
            var dave = new Person Id = 2;

            bob.Friends.Add(scott);
            bob.Friends.Add(dave);
            scott.Friends.Add(dave);

            var people = new List<Person>();
            people.Add(bob);
            people.Add(scott);
            people.Add(dave);

            using (var fs = File.Create("Test.xml"))
            
                var ser = new DataContractSerializer(typeof(List<Person>));
                ser.WriteObject(fs, people);
            

            List<Person> people2;
            using (var fs = File.OpenRead("Test.xml"))
            
                var ser = new DataContractSerializer(typeof(List<Person>));
                people2 = (List<Person>)ser.ReadObject(fs);
            

            Console.WriteLine("Are these daves the same dave?");
            Console.WriteLine("List dave, bob's friend - 0", ReferenceEquals(people2[2], people2[0].Friends[1]));
            Console.WriteLine("Bob's firend, scott's friend - 0", ReferenceEquals(people2[0].Friends[1], people2[1].Friends[0]));
            Console.ReadLine();
        
    

    [DataContract(IsReference = true)]
    public class Person
    
        public Person()
        
            Friends = new List<Person>();
        

        [DataMember]
        public int Id  get; set; 

        [DataMember]
        public List<Person> Friends  get; private set; 
    

尝试使用IsRefrence = false或不带参数(默认为false)运行上面的测试程序,它将输出false用于测试是同一个对象。但是,如果您将其设置为 IsRefrence = false,它将输出 true 以用于作为同一对象的测试。

编辑:重要的一点,我不知道如何让RefrenceEquals(people[0], people2[0]) 输出true

【讨论】:

以上是关于在维护对象引用的同时序列化 C# 对象的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 中序列化和反序列化自引用对象

C# 中的弱引用 WeakReference

C# 对象与 JSON 字符串的相互转换

在 C# 中通过引用传递对象和对象列表

C#连接数据库出现未将对象引用实例

serialVersionUID的作用