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

Posted

技术标签:

【中文标题】如何将参数传递给反序列化json的构造函数【英文标题】:How to pass parameter to constructor deserializing json 【发布时间】:2016-03-24 21:45:00 【问题描述】:

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

非常感谢!

【问题讨论】:

如果你真的需要这个,你可能想改变你的设计。如果你不能序列化然后反序列化和对象,你不应该在序列化中使用它。 我没有收到任何错误消息,传递的值只是null。改变架构是不可能的,因为这会导致大量的重构工作。 我的意思是如果你的类依赖于一个内部成员,你不能简单地反序列化它。默认情况下,序列化仅适用于公共成员。您可能希望公开 A,或以其他方式使其可序列化。 目前我没有内部成员。那么,公开A 是什么意思? A 不仅会在ctor中使用。我只是想简化这个问题。但是A有一些属性和方法,需要从B访问 【参考方案1】:

在您的问题和 cmets 中,您说过 B 类没有 A 的任何公共财产。所以,当你序列化B时,不会有A被写入JSON,因为Json.Net默认只序列化公开信息。因此,在反序列化时,将没有足够的信息来重新创建B,因为JSON 中没有A。因此,第一步是让 BA 的引用对 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 有一个 Bs 列表,每个都引用 A),并且序列化程序将在这种情况下默认抛出异常。解决方案是将序列化程序的PreserveReferencesHandling 设置为Objects(默认为None)。这不仅允许序列化程序在序列化期间处理引用循环,而且还将在反序列化期间保留原始引用,以便所有Bs 将引用相同的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

【讨论】:

完美运行,正是我想要的!非常感谢! 没问题;很高兴我能帮上忙。【参考方案2】:

我喜欢做的是我必须在构造函数中传递对象是首先使用我的默认构造函数创建对象,然后调用填充对象来设置所有未跳过的属性,因为我使用 [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);

【讨论】:

以上是关于如何将参数传递给反序列化json的构造函数的主要内容,如果未能解决你的问题,请参考以下文章

如何将参数传递给正则表达式构造函数,并在 String.matchAll 方法中使用 [重复]

PyQt4 将转换矩阵作为参数传递给构造函数

当我们将对象作为参数传递给方法时,为啥会调用复制构造函数?

c++ 在创建时将构造函数参数从父对象传递给子对象

.NET Core DI,将参数传递给构造函数的方法

如何将参数传递给静态类构造函数?