Newtonsoft.Json
を使用してオブジェクトを逆シリアル化するときに、親インスタンスをコンストラクターに渡す際に小さな問題が発生します。
私が次のクラスを持っていると仮定しましょう
public class A
{
public string Str1 { get; set; }
public IList<B> Bs { get; set; }
}
public class B
{
public B(A a)
{
// a should not be null!
Console.WriteLine(a.Str)
}
}
そして今、私は次のようにオブジェクトa
をserailzeして逆シリアル化します。
A a = new A()
a.Bs = new List<B>()
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
a.Bs.Add(new B(a));
var json = JsonConvert.SerializeObject(a);
// Here i need to call the constructor of B when creating new instances
var newA = JsonConvert.DeserializeObject<A>(json);
問題は、オブジェクトを逆シリアル化するときに、null
がB
のコンストラクターに渡されることです。誰かが以前にこの問題/問題を解決したことがありますか?
どうもありがとうございました!
あなたの質問とコメントで、クラスB
にはA
のパブリックプロパティがないと述べました。したがって、B
をシリアル化すると、Json.Netはデフォルトで公開情報のみをシリアル化するため、A
はJSONに書き込まれません。したがって、逆シリアル化する場合、JSONにB
がないため、A
を再作成するのに十分な情報がありません。したがって、ステップ1は、B
のA
への参照をJson.Netに表示することです。公開したくない場合は問題ありませんが、少なくともメンバーを[JsonProperty]
属性でマークして、Json.Netがそれを「参照」できるようにする必要があります。
public class B
{
[JsonProperty]
private A a;
public B(A a)
{
this.a = a; // be sure to set the A member in your constructor
}
}
上記を実行すると、2番目の問題が発生します。クラス構造に参照ループがあります(A
にはそれぞれがB
を参照するA
sのリストがあります) 、この場合、シリアライザーはデフォルトで例外をスローします。解決策は、シリアライザーの PreserveReferencesHandling
設定をObjects
に設定することです(デフォルトはNone
です)。これにより、シリアライザがシリアル化中に参照ループを処理できるようになるだけでなく、逆シリアル化中に元の参照が保持されるため、すべてのB
sが同じA
インスタンスを参照するようになります。 (これは、JSONに書き込まれる特別な$id
および$ref
プロパティを介して実行されます。)
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
var json = JsonConvert.SerializeObject(a, settings);
var newA = JsonConvert.DeserializeObject<A>(json, settings);
コンストラクターでオブジェクトを渡す必要があるのは、最初にデフォルトコンストラクターを使用してオブジェクトを作成し、次にpopulateオブジェクトを呼び出して、プロパティを[JsonIgore]で装飾したときにスキップされないすべてのプロパティを設定することです。
var settings = new JsonSerializerSettings()
{
Error = HandleJsonDeserializationError,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
}
var myObject = new ComplexObject(param1,param2);
JsonConvert.PopulateObject(json, myObject, settings);
JsonSettingsプロパティでシリアル化エラーを処理すれば、オブジェクトの入力を続行して問題に対処できます。署名は次のとおりです。
static void HandleJsonDeserializationError(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs errorArgs)
{
var currentError = errorArgs.ErrorContext.Error.Message;
errorArgs.ErrorContext.Handled = true;
//loging framework logs the error, set brake point etc when debug.
Logger.Log(currentError, LogLevel.Exceptions);
}