我有一个遗留应用程序使用二进制序列化来保存数据。现在我们想使用 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 对此。谢谢大家的回答,投票...
最佳答案
我认为您需要 ReferenceLoopHandling.Serialize
和 PreserveReferencesHandling.All
来复制二进制序列化的行为。不过,生成的 JSON 可能没有那么漂亮。
编辑:我深入研究了 JSON.Net 4.5r10 并发现了一个缺陷:JsonSerializerInternalWriter
不检查 #ShouldWriteReference
通过 ISerializable
获得的引用。
#SerializeISerializable
中的 foreach
循环重写如下,您的对象图成功往返。
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);
}
}
关于c# - 使用 ReferenceLoopHandling.Ignore 序列化循环依赖的 ISerializable 对象时抛出 StackOverflowException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13412359/