当前位置: 首页 > 面试题库 >

使用ReferenceLoopHandling.Ignore序列化依赖于循环的ISerializable对象时,抛出StackOverflowException。

相弘方
2023-03-14
问题内容

我有一个使用二进制序列化来保留数据的旧版应用程序。现在,我们想使用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 :当循环引用对象不为null时,实际上序列化本身不起作用

Edit4 :来自Json.net问题库的评论是问题在您的末端,并已解决问题。但是我找不到我的代码出了什么问题。我对此发布了另一个


问题答案:

我想你会需要同时ReferenceLoopHandling.SerializePreserveReferencesHandling.All复制二进制序列化的行为。但是,生成的JSON可能不那么漂亮。

编辑: 我对JSON.Net4.5r10进行了更深入的研究,发现了一个缺陷:JsonSerializerInternalWriter不检查#ShouldWriteReference通过获得的引用ISerializable

随着foreach循环中#SerializeISerializable,如下改写,你的对象图顺利往返。

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


 类似资料:
  • 我试图用jackson序列化一些数据,这在大多数情况下都很好,但现在我对列表有问题。该列表的类型为 A,它是一个抽象类,可能包含循环依赖项。我不知道如何使用 jackson 序列化这个结构。IdentityInformation和typeInformation的组合似乎无法正常工作。下面是示例代码,它产生了我面临的问题。 我使用的是 Jackson 版本 2.8.3。我错过了什么吗?有没有一个好的

  • 问题内容: 我有一个对象(解析树),其中包含子节点,这些子节点是对其他节点的引用。 我想使用序列化此对象,但是我得到了 TypeError:循环对象值 因为我提到的结构。 我该如何解决?对我而言,在序列化对象中是否表示对其他节点的引用并不重要。 另一方面,在创建对象时从对象中删除这些属性似乎很乏味,我也不想对解析器(水仙)进行更改。 问题答案: 使用的第二个参数,该替代品的功能,以排除已序列化对象

  • 问题内容: 好的,所以我想用杰克逊json转换器测试一些东西。我正在尝试模拟图形行为,所以这些是我的POJO实体 标签是必需的,以避免序列化时出现异常。当我尝试序列化一个对象(在文件或简单字符串上)时,一切正常。但是,当我尝试反序列化对象时,它将引发异常。这是简单的测试方法(为简单起见,省略了try / catch) 这是抛出的异常(当然,重复两次) 那么,问题的原因是什么呢?我该如何解决?我还需

  • 问题内容: 好的,所以我想用杰克逊json转换器测试一些东西。我正在尝试模拟图形行为,所以这些是我的POJO实体 标签是必需的,以避免序列化时出现异常。当我尝试序列化一个对象(在文件或简单字符串上)时,一切正常。但是,当我尝试反序列化对象时,它将引发异常。这是简单的测试方法(为简单起见,省略了try / catch) 这是抛出的异常(当然,重复两次) 那么,问题的原因是什么呢?我该如何解决?我还需

  • 问题内容: 上课: 和控制器代码: 它适用于LOCALHOST,但不适用于实时服务器: 错误: Json序列化类型的对象时检测到循环引用 我进行了搜索并找到了属性,因此将模型更改为 但是在实时服务器(win2008)上也会发生相同的错误。 如何避免该错误并成功序列化父数据? 问题答案: 尝试以下代码: …或者如果您仅需要父属性: 它并不是解决问题的真正方法,但在序列化DTO时是一种常见的解决方法。

  • 问题内容: 我正在尝试做一个简单的JSON返回,但是我遇到以下问题。 我得到一个HTTP 500,但此问题的标题中显示了例外。我也试过 那也带来了同样的问题。 这是错误还是我的实现? 问题答案: 看来您的对象层次结构中有循环引用,而JSON序列化程序不支持。您是否需要所有列?您只能在视图中选择所需的属性: 这将使您的JSON对象更轻便,更易于理解。如果您有许多属性,则可以使用AutoMapper