本文介绍了与ReferenceLoopHandling.Ignore连载循环依赖ISerializable的对象时StackOverflowException被抛出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用二进制序列化到持久化数据的遗留应用程序。现在我们想利用Json.net 4.5没有太大的变化数据序列化到现有的类。

I have a legacy application that used binary serialisation to persist the data. Now we wanted to use Json.net 4.5 to serialise the data without much changes to the existing classes.

事情是工作不错。有没有什么解决办法来解决这个问题?

Things were working nice till we hit a circular dependent class. Is there any workaround to solve this problem?

$示例如下图所示。

[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 );
    }
}

和测试code

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.$c$cplex.com/workitem/23668)

Edit1: The issue has been reported to Json (http://json.codeplex.com/workitem/23668)

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

Edit2: Serialization works fine in version 4.5 R11 but de-serialization still not working

EDIT3 :其实序列化本身,当循环引用的对象不是null不能正常工作

Edit3: Actually Serialization itself is not working when circular reference object is not null

Edit4 :从Json.net问题基础的评论是,问题出在你的结束,关闭了该问题。但我无法找出什么是错我的code。我张贴另一个 question关于这一点。谢谢大家的回答,投票了......

Edit4: Comment from the Json.net issue base is that the problem is at your end and closed the issue. But i could not find out what is wrong with my code. I posted another question regarding this. Thank you all for answering, voting...

推荐答案

我认为你需要两个 ReferenceLoopHandling.Serialize preserveReferencesHandling.All 复制二进制序列化的行为。由此产生的JSON可能不是几乎一样pretty的,虽然。

I think you'll need both ReferenceLoopHandling.Serialize and PreserveReferencesHandling.All to replicate the behavior of binary serialization. The resulting JSON may not be nearly as pretty, though.

编辑:我看深入JSON.Net 4.5r10并发现了一个缺陷: JsonSerializerInternalWriter 不检查 #ShouldWriteReference 通过 ISerializable的

I've looked deeper into JSON.Net 4.5r10 and discovered a deficiency: JsonSerializerInternalWriter doesn't check #ShouldWriteReference for references obtained via ISerializable.

随着的foreach 环路 #SerializeISerializable 改写如下,您的对象图的往返成功。

With the foreach loop in #SerializeISerializable rewritten as below, your object graph round-trips successfully.

  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);
    }
  }

这篇关于与ReferenceLoopHandling.Ignore连载循环依赖ISerializable的对象时StackOverflowException被抛出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-23 15:01