[英]Json.net: Serialisation/Deserialisation not working for ISerializable object that has circular reference
一段時間后我報告了一個問題 ,我在Json.net 4.5 R11中得到了修復。
如果我的循環引用屬性Manager
為NULL,則序列化和反序列化工作正常。
但是當循環引用屬性Manager
設置為NON NULL值時,它會在序列化字符串中被忽略,因此它會在反序列化中引發異常。
Json.net問題庫說問題出在你的代碼中,但我無法弄明白。 有人可以幫我嗎?
問題:
一些更新 :在當前使用二進制序列化的遺留應用程序中需要這樣做。 由於更改很大,因此使用Json序列化標記標記序列化中涉及的所有私有字段的工作量太大。 由於Json.net可以對ISerializable對象進行序列化,我們希望這樣做。 如果沒有循環引用對象,則此方法有效。
我的課程
[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 ) ); //Manager's data not found since json string itself does not have Employee property
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
{
public Department Department { get; set; }
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 );
}
}
我的測試代碼:
JsonSerializerSettings jsonSS= new JsonSerializerSettings();
jsonSS.Formatting = Formatting.Indented;
jsonSS.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; //If there is referenced object then it is not shown in the json serialisation
//jsonSS.ReferenceLoopHandling = ReferenceLoopHandling.Serialize; //Throws stackoverflow error
jsonSS.PreserveReferencesHandling = PreserveReferencesHandling.All;
Department department = new Department();
department.Name = "Dept1";
Employee emp1 = new Employee { Name = "Emp1", Department = department };
department.Manager = null;
string json1 = JsonConvert.SerializeObject( emp1, jsonSS );
//json1 =
// {
// "$id": "1",
// "Department": {
// "$id": "2",
// "Manager": null,
// "Name": "Dept1"
// },
// "Name": "Emp1"
//}
Employee empD1 = JsonConvert.DeserializeObject<Employee>( json1, jsonSS ); //Manager is set as null
department.Manager = emp1; //Non null manager is set
string json2 = JsonConvert.SerializeObject( emp1, jsonSS ); //SEE Manager property is missing
// json2 = {
// "$id": "1",
// "Department": {
// "$id": "2",
// "Name": "Dept1"
// },
// "Name": "Emp1"
//}
Employee empD2 = JsonConvert.DeserializeObject<Employee>( json2, jsonSS ); //Throws exception
基於khellang的答案,它定位了JSon.Net中的問題,在使用ISerializable
接口實現時無法處理循環引用,您可以嘗試強制JSon.Net序列化程序忽略ISerializable
實現,而不實際刪除此實現。
您應該能夠通過使用JsonObject
屬性修飾類( Department
和Employee
)來實現此目的。
我還沒有測試這是否真的解決了你的問題。
引用序列化指南 (強調我的):
實現ISerializable的類型被序列化為JSON對象。 序列化時,僅使用從ISerializable.GetObjectData返回的值; 該類型的成員將被忽略。 反序列化時,調用帶有SerializationInfo和StreamingContext的構造函數,傳遞JSON對象的值。
在不需要此行為的情況下,可以將JsonObjectAttribute放置在實現ISerializable的.NET類型上,以強制將其序列化為普通的JSON對象。
由於您的問題和評論可以追溯到2012年,因此可能無法使用此解決方案。 即使使用ISerializable
,當前的JSon.Net實現也可以處理循環引用。
但是當循環引用屬性管理器設置為NON NULL值時,它會在序列化字符串中被忽略,因此它會在反序列化中引發異常。
因為循環引用被忽略了。 這就是ReferenceLoopHandling.Ignore的要點。
PreserveReferencesHandling不適用於ISerializable,因為必須在父值之前創建子值。
看起來你真的不需要實現Iserializable接口。 這種類結構很簡單。 我已經序列化了非常大的類而不必走那么遠。
如果您仍有循環引用問題,請嘗試以下操作:
我相信JSON.net有一個格式化選項來忽略循環引用
JsonSerializerSettings jsSettings = new JsonSerializerSettings(); jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
忽略違規財產
重組你的課程
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.