5

しばらく前に、Json.net 4.5 R11 で修正された問題を報告しました。

循環参照プロパティManagerが NULL の場合、シリアル化と逆シリアル化は正常に機能します。

ただし、循環参照プロパティManagerが NON NULL 値に設定されている場合、シリアル化された文字列では無視されるため、逆シリアル化で例外がスローされます。

Json.netの問題ベースは、問題はあなたのコードにあると言いますが、私は理解できませんでした。誰かがここで私を助けることができますか?

質問:

  1. 以下のコードに問題はありますか?
  2. はいの場合、問題を解決するにはどうすればよいですか?
  3. そうでない場合、この問題を解決するために 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
4

4 に答える 4

3

インターフェイス実装を使用しているときに JSon.Net が循環参照を処理できないという問題を特定するkhellangの回答に基づいて、この実装を実際に削除せずにISerializable、JSon.Net シリアライザーに強制的に実装を無視させることができます。クラス(および)を属性で 装飾することで、これを実現できるはずです。 これで実際に問題が解決するかどうかはテストしていません。ISerializable
DepartmentEmployeeJsonObject

シリアライゼーションガイドを引用する(強調鉱山):

ISerializable を実装する型は、JSON オブジェクトとしてシリアル化されます。シリアライズ時には、ISerializable.GetObjectData から返された値のみが使用されます。型のメンバーは無視されます。逆シリアル化すると、SerializationInfo と StreamingContext を持つコンストラクターが呼び出され、JSON オブジェクトの値が渡されます。

この動作が望ましくない状況では、ISerializable を実装する .NET 型に JsonObjectAttribute を配置して、通常の JSON オブジェクトとして強制的にシリアル化することができます。

あなたの質問とコメントは 2012 年にさかのぼるため、このソリューションは当時利用できなかった可能性があります。また、現在の JSon.Net 実装は、使用されている場合でも循環参照を処理できる可能性がありISerializableます。

于 2016-12-30T22:03:31.423 に答える
1

短くしておきます:)

  1. それISerializableを台無しにするのはインターフェースのようです。削除すると、すべてが完全に機能します。

  2. とにインターフェースを実装する本当に正当な理由がありますか?そうでない場合は、削除してください。もしそうなら、GOTO 3;)ISerializableEmployeeDepartment

  3. Newtonsoft.Jsonの内部はわかりませんが、実装時に循環参照が適切に処理されていませんISerializable。おそらくGitHubで問題を報告する必要があります。

于 2012-12-12T16:32:10.030 に答える
1

ただし、循環参照プロパティManagerがNON NULL値に設定されている場合、シリアル化された文字列では無視されるため、逆シリアル化で例外がスローされます。

循環参照が無視されているためです。それがReferenceLoopHandling.Ignoreのポイントです。

親値の前に子値を作成する必要があるため、PreserveReferencesHandlingはISerializableでは機能しません。

于 2012-12-15T21:53:24.697 に答える
-2

Iserializableインターフェースを実際に実装する必要があるようには見えません。このクラス構造は単純な方法です。私はそれほど遠くまで行かなくても、非常に大きなクラスをシリアル化しました。

それでも循環参照の問題が発生する場合は、次のことを試してください。

  1. JSON.netには循環参照を無視するフォーマットオプションがあると思います

    JsonSerializerSettings jsSettings = new JsonSerializerSettings(); jsSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

  2. 問題のあるプロパティを無視する

  3. クラスを再構築する

于 2012-12-14T14:41:23.617 に答える