7

バイナリ シリアル化を使用してデータを永続化するレガシー アプリケーションがあります。ここで、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 issue base からのコメントは、問題はあなたの側にあり、問題を解決したということです。しかし、コードの何が問題なのかを見つけることができませんでした。これに関して別の質問を投稿しました。回答、投票ありがとうございます...

4

2 に答える 2

6

バイナリ シリアル化の動作を再現するには、ReferenceLoopHandling.Serializeとの両方が必要になると思います。PreserveReferencesHandling.Allただし、結果として得られる JSON はそれほどきれいではないかもしれません。

編集: JSON.Net 4.5r10 を詳しく調べたところ、欠陥が見つかりました:経由で取得した参照をJsonSerializerInternalWriterチェックしません。#ShouldWriteReferenceISerializable

以下のように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);
    }
  }
于 2012-11-16T07:46:01.987 に答える
0

これを試しましたか?

[Serializable]
 class Employee : ISerializable
 {
   [NonSerialized]
   [XmlIgnore]
   public Department Department { get; set; }

NonSerializedシリアライズ可能なクラスのフィールドをシリアライズしてはならないことを示します。

XmlIgnore XmlSerializerの Serialize メソッドに、パブリック フィールドまたはパブリックの読み取り/書き込みプロパティ値をシリアル化しないように指示します。

于 2012-11-16T09:07:52.927 に答える