• 一个C#序列化时循环引用的问题


    以前一直没搞懂为什么C#在做对象序列化时(Json序列化,XML序列化等)有时候会出现循环引用的问题,下面写了个例子,类People有一个属性引用了类Child,而类Child也有一个属性引用了类People,并且两个属性的get访问器中都会new一个彼此类型的对象,这样在访问People类的Child属性的时候就会new一个Child对象,在访问Child类的People属性的时候又会new一个People对象。所以C#序列化方法在序列化People类的Child属性时又会去序列化Child属性返回的Child对象,而在序列化Child类的People属性时又会去序列化People属返回的People对象。那么C#序列化方法在检测People类和Child类的属性的时候就会不停地去构造(不停地new)且不停地序列化People对象和Child对象,形成一个死循环:People->Child->People->Child->People....,所以就会抛出循环引用的异常,注意下面XML序列化的时候只有属性声明了set访问器才会出现循环引用的异常,说明C#自带的XmlSerializer比JavaScriptSerializer要更先进一些。。。

    类Child:

     1 using System.Xml;
     2 using System.Xml.Serialization;
     3 
     4 namespace SE
     5 {
     6     [XmlRoot]
     7     public class Child
     8     {
     9         public Child()
    10         {
    11         }
    12 
    13         [XmlElement]
    14         public string Name { get; set; }
    15 
    16         [XmlElement]
    17         public int Age { get; set; }
    18         
    19 
    20         [XmlElement]
    21         public People People
    22         {
    23             //注意属性声明了set访问器XmlSerializer在序列化时才会出现循环引用异常
    24             /*set
    25             {
    26 
    27             }*/
    28             get
    29             {
    30                 return new People();
    31             }
    32         }
    33     }
    34 }

    类People:

     1 using System.Xml;
     2 using System.Xml.Serialization;
     3 
     4 namespace SE
     5 {
     6     [XmlRoot]
     7     public class People
     8     {
     9         public People()
    10         {
    11         }
    12 
    13         [XmlElement]
    14         public string Name { get; set; }
    15 
    16         [XmlElement]
    17         public int Age { get; set; }
    18         
    19 
    20         [XmlElement]
    21         public Child Child
    22         {
    23             //注意属性声明了set访问器XmlSerializer在序列化时才会出现循环引用异常
    24             /*set
    25             {
    26 
    27             }*/
    28             get
    29             {
    30                 return new Child();
    31             }
    32         }
    33     }
    34 }


    序列化调用代码:

     1 using System;
     2 using System.Web.Script.Serialization;
     3 using System.IO;
     4 using System.Xml.Serialization;
     5 
     6 namespace SE
     7 {
     8     class Program
     9     {
    10         static void Main(string[] args)
    11         {
    12             People P = new People() { Name = "James", Age = 15};
    13             XmlSerializer xmls = new XmlSerializer(P.GetType());
    14             string content;
    15             using (MemoryStream ms = new MemoryStream())
    16             {
    17                 xmls.Serialize(ms, P);//如果People类和Child类的属性有set访问器则抛出循环引用异常
    18                 ms.Position = 0;
    19                 using (StreamReader s = new StreamReader(ms))
    20                 {
    21                     content = s.ReadToEnd();
    22                 }
    23             }
    24 
    25             Console.ReadLine();
    26 
    27             JavaScriptSerializer js = new JavaScriptSerializer();
    28             content=js.Serialize(P);//抛出循环引用异常
    29             Console.ReadLine();
    30         }
    31     }
    32 }
  • 相关阅读:
    大话设计模式-原型模式
    Unity3D实习生面试题总结-图形学相关
    UnityShader入门精要-渲染流水线
    大话设计模式-工厂方法模式
    大话设计模式-代理模式
    C#中的值类型和引用类型
    【树结构】树链剖分简单分析
    HEOI2016排序-解题报告
    普通筛法时间界的证明
    可持久化线段树
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/5065239.html
Copyright © 2020-2023  润新知