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

我有一个遗留应用程序,它使用二进制序列化来保存数据。 现在我们想使用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 employees = new List(); employees.Add( emp1 ); employees.Add( emp2 ); var memoryStream = new MemoryStream(); var formatter = new BinaryFormatter(); formatter.Serialize( memoryStream, employees ); memoryStream.Seek( 0, SeekOrigin.Begin ); IList deserialisedEmployees = formatter.Deserialize( memoryStream ) as IList; //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 

编辑1 :该问题已报告给Json( http://json.codeplex.com/workitem/23668 )

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

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

编辑4 :来自Json.net问题基础的评论是问题在你的最后并关闭了问题。 但我无法找出我的代码有什么问题。 我发布了另一个问题 。 谢谢大家回答,投票……

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

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

使用#SerializeISerializableforeach循环重写如下,您的对象图成功往返。

  foreach (SerializationEntry serializationEntry in serializationInfo) { writer.WritePropertyName(serializationEntry.Name); var entryValue = serializationEntry.Value; var valueContract = GetContractSafe(entryValue); if (ShouldWriteReference(entryValue, null, valueContract, null, member)) { WriteReference(writer, entryValue); } else { SerializeValue(writer, entryValue, valueContract, null, null, member); } } 

你试过这个吗?

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

NonSerialized指示不应序列化可序列化类的字段。

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