如何将参数传递给构造函数反序列化json

时间:2015-12-18 08:22:48

标签: c# json serialization json.net deserialization

在使用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的构造函数。有没有人之前解决过这个问题?

非常感谢!

2 个答案:

答案 0 :(得分:10)

在您的问题和评论中,您说过B课程没有A的任何公共财产。因此,当您序列化B时,不会将A写入JSON,因为Json.Net默认只序列化公共信息。因此,在反序列化时,没有足够的信息来重新创建B,因为JSON中没有A。因此,第一步是B对Json.Net可见的A的引用。如果您不想将其公开,那很好,但您至少需要使用[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

答案 1 :(得分:0)

我想做的是,我必须在构造函数中传递对象是先使用默认构造函数创建对象,然后调用populate对象设置所有不跳过的属性,因为我用[JsonIgore]装饰了属性< / p>

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