Json.net:序列化/反序列化不适用于具有循环引用的 ISerialized 对象

key*_*eyr 5 .net c# serialization json json.net

一段时间前,我报告了一个问题,我已在 Json.net 4.5 R11 中修复了该问题。

如果我的循环引用属性Manager为 NULL,则序列化和反序列化工作正常。

但是,当循环引用属性Manager设置为 NON NULL 值时,它会在序列化字符串中被忽略,因此会在反序列化时引发异常。

Json.net 问题库说问题出在您的代码中,但我无法弄清楚。有人可以帮我吗?

问题:

  1. 下面的代码有问题吗?
  2. 如果是的话我应该怎么做才能解决这个问题?
  3. 如果不是那么应该在 Json.net 代码中做什么来解决这个问题?

更多更新:当前使用二进制序列化的遗留应用程序需要此更新。由于变化巨大,用Json序列化标签标记所有涉及序列化的私有字段的工作量太大。由于 Json.net 可以对 ISerialized 对象进行序列化,因此我们希望这样做。如果没有循环引用对象,这将起作用。

我的课程

[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 );
    }
}
Run Code Online (Sandbox Code Playgroud)

我的测试代码:

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
Run Code Online (Sandbox Code Playgroud)

khe*_*ang 1

我会长话短说:)

  1. 看来是ISerializable接口搞砸了。如果你删除它,一切都会完美。

  2. 您是否有充分的理由ISerializableEmployee和中实现该接口Department?如果没有,只需将其删除即可。如果你这样做,请转到 3 ;)

  3. 我不知道Newtonsoft.Json 的内部结构,但不知何故,它在实现ISerializable. 您可能应该在GitHub上提交问题。