使用ReferenceLoopHandling.Ignore序列化循环相关的ISerializable对象时抛出StackOverflowException

时间:2012-11-16 07:40:35

标签: c# .net json serialization json.net

我有一个使用二进制序列化来保存数据的遗留应用程序。现在我们想使用Json.net 4.5来序列化数据而不需要对现有类进行太多更改。

在我们打了一个循环的依赖课程之前,事情很顺利。有没有解决这个问题的解决方法?

示例代码如下所示

[Serializable]
class Department : ISerializable
{
    public Employee Manager { get; set; }
    public string Name { get; set; }

    public Department() { }
    public Department( SerializationInfo info, StreamingContext context )
    {
        Manager = ( Employee )info.GetValue( "Manager", typeof( Employee ) );
        Name = ( string )info.GetValue( "Name", typeof( string ) );
    }
    public void GetObjectData( SerializationInfo info, StreamingContext context )
    {
        info.AddValue( "Manager", Manager );
        info.AddValue( "Name", Name );
    }
}

[Serializable]
class Employee : ISerializable
{
    [NonSerialized] //This does not work
    [XmlIgnore]//This does not work
    private Department mDepartment;
    public Department Department
    {
        get { return mDepartment; }
        set { mDepartment = value; }
    }

    public string Name { get; set; }

    public Employee() { }
    public Employee( SerializationInfo info, StreamingContext context )
    {
        Department = ( Department )info.GetValue( "Department", typeof( Department ) );
        Name = ( string )info.GetValue( "Name", typeof( string ) );
    }

    public void GetObjectData( SerializationInfo info, StreamingContext context )
    {
        info.AddValue( "Department", Department );
        info.AddValue( "Name", Name );
    }
}

测试代码

Department department = new Department();
department.Name = "Dept1";

Employee emp1 = new Employee { Name = "Emp1", Department = department };
department.Manager = emp1;

Employee emp2 = new Employee() { Name = "Emp2", Department = department };
IList<Employee> employees = new List<Employee>();
employees.Add( emp1 );
employees.Add( emp2 );

var memoryStream = new MemoryStream();
var formatter = new BinaryFormatter();
formatter.Serialize( memoryStream, employees );

memoryStream.Seek( 0, SeekOrigin.Begin );
IList<Employee> deserialisedEmployees = formatter.Deserialize( memoryStream ) as IList<Employee>; //Works nicely

JsonSerializerSettings jsonSS= new JsonSerializerSettings();
jsonSS.TypeNameHandling = TypeNameHandling.Objects;
jsonSS.TypeNameAssemblyFormat = FormatterAssemblyStyle.Full;
jsonSS.Formatting = Formatting.Indented;
jsonSS.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //This is not working!!
//jsonSS.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; //This is also not working!!
jsonSS.PreserveReferencesHandling = PreserveReferencesHandling.All;
string jsonAll = JsonConvert.SerializeObject( employees, jsonSS ); //Throws stackoverflow exception

Edit1 :此问题已报告给Json(http://json.codeplex.com/workitem/23668

Edit2 :序列化在版本4.5 R11中正常工作但反序列化仍无法正常工作

Edit3 :当循环引用对象不为空时,实际上序列化本身不起作用

Edit4 :来自Json.net问题基础的评论是问题在您的最后并解决了问题。但我无法找出我的代码有什么问题。我发布了另一个 question 。谢谢大家回答,投票......

2 个答案:

答案 0 :(得分:5)

我认为你需要ReferenceLoopHandling.SerializePreserveReferencesHandling.All来复制二进制序列化的行为。但是,生成的JSON可能不会那么漂亮。

编辑:我更深入地研究了JSON.Net 4.5r10并发现了一个缺陷:JsonSerializerInternalWriter没有检查#ShouldWriteReference是否通过{{1}获得的引用}。

如下所示重写ISerializable中的foreach循环,您的对象图就会成功往返。

#SerializeISerializable

答案 1 :(得分:0)

你试过这个吗?

[Serializable]
 class Employee : ISerializable
 {
   [NonSerialized]
   [XmlIgnore]
   public Department Department { get; set; }
  

NonSerialized 表示可序列化类的字段应该   不被序列化。

     

XmlIgnore 指示 XmlSerializer 的Serialize方法不要   序列化公共字段或公共读/写属性值