如何将参数传递给反序列化json的构造函数
本文关键字:json 构造函数 反序列化 参数传递 | 更新日期: 2023-09-27 18:27:14
在使用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
,如下所示:
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写入A
,因为JSON.Net默认情况下只序列化公共信息。因此,在反序列化时,将没有足够的信息来重新创建B
,因为JSON中没有A
。因此,第一步是让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
}
}
现在,如果您执行上述操作,您将遇到第二个问题:您的类结构有一个引用循环(A
有一个B
的列表,每个列表都引用回A
),在这种情况下,序列化程序默认会抛出一个异常。解决方案是将序列化程序的PreserveReferencesHandling
设置设置为Objects
(默认为None
)。这不仅允许序列化程序在序列化期间处理引用循环,而且还将在反序列化期间保留原始引用,以便所有B
都将引用同一个A
实例。(这是通过写入JSON的特殊$id
和$ref
属性来实现的。)
JsonSerializerSettings settings = new JsonSerializerSettings
{
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
};
var json = JsonConvert.SerializeObject(a, settings);
var newA = JsonConvert.DeserializeObject<A>(json, settings);
工作示例:https://dotnetfiddle.net/N0FUID
我喜欢做的是,我必须在构造函数中传递对象,首先使用我的默认构造函数创建对象,然后调用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);
}