将Newtonsoft.Json与嵌套的自定义类一起使用

时间:2017-01-09 15:39:17

标签: c# json serialization json.net

我需要序列化一些自定义对象才能存储信息。但是,我正在努力将序列化JSON字符串中的这些对象反序列化为其原始对象形式。

序列化字符串似乎很好:

[
  {
    "MyStringArray": [
      "stringInput1",
      "stringInput2"
    ],
    "MyCharArray": [
      "a",
      "b",
      "c",
      "."
    ],
    "MyString": "dummy",
    "MyClass3Object": [
      {
        "MyString": "ListInput1"
      },
      {
        "MyString": "ListInput2"
      }
    ]
  }
]

但是,当我重建原始的MyClass1对象时,列表中应该有一个条目,但是它用空值而不是相应的数据填充。关于可能发生的事情的任何想法?提前感谢头脑风暴:)

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using System.IO;
using System.Text.RegularExpressions;

namespace JsonTesting
{
  class Program
  {
    static void Main(string[] args)
    {

      MyClass1 c1 = new MyClass1();
      c1.AddInfo();

      string toJsonString = JsonConvert.SerializeObject(c1, Formatting.Indented,
        new JsonSerializerSettings { DefaultValueHandling = DefaultValueHandling.Include });
      File.WriteAllText(@"C:\temp\dumpJsonText.txt",toJsonString);
      MyClass1 fromJson = JsonConvert.DeserializeObject<MyClass1>(toJsonString);
      Console.ReadLine();

    }
  }


  public class MyClass1 : List<MyClass2> {
    public MyClass1() { }
    public void AddInfo() {
      this.Add(new MyClass2(new string[] { "stringInput1", "stringInput2" },
        new char[] { 'a', 'b', 'c', '.' },
        "dummy",
        new List<MyClass3>() { new MyClass3("ListInput1", new Regex(@"[A-Z]")), new MyClass3("ListInput2", new Regex(@"[0-9]")) }
        ));
    }
  }

  public class MyClass2
  {
    private string[] _myStringArray = null;
    private char[] _myCharArray = null;
    private string _myString = null;
    private List<MyClass3> _myClass3Object = null;

    public MyClass2() { }

    public MyClass2(string[] myStringArray, char[] myCharArray, string myString, List<MyClass3> myClass3Object)
    {
      _myStringArray = myStringArray;
      _myCharArray = myCharArray;
      _myString = myString;
      _myClass3Object = myClass3Object;
    }

    public string[] MyStringArray { get { return _myStringArray; } }
    public char[] MyCharArray { get { return _myCharArray; } }
    public string MyString { get { return _myString; } }
    public List<MyClass3> MyClass3Object { get { return _myClass3Object; } }

  }

  public class MyClass3 {

    private Regex _myRegex; 
    private string _myString = null;
    public MyClass3() { }
    public MyClass3(string myString, Regex myRegex) {

      _myString = myString;
      _myRegex = myRegex;
    }

    public string MyString{ get {return _myString;} }

  }

}

1 个答案:

答案 0 :(得分:1)

您的课程MyClass2MyClass3是只读的。为了让Json.NET反序列化只读类型,您必须提供一个custom JsonConverter来手动反序列化并构造该类型的实例,或者提供一个参数化构造函数,其参数名称与属性名称匹配模数。您已经创建了必要的构造函数,因此已经完成了一半。

但是你的类型也有无参数构造函数。那么,Json.NET调用哪个构造函数?对于序列化为JSON object的非可枚举类型,以下规则适用:

  1. 如果在构造函数上设置了[JsonConstructor],请使用该构造函数。

  2. 接下来,在full trust only中,当应用 MemberSerialization.Fields 或应用[Serializable]DefaultContractResolver.IgnoreSerializableAttribute == false时,特殊方法{ {3}}用于分配对象。 不会调用任何类型的构造函数。

    (这是一种不常见的情况。)

  3. 接下来,如果有一个公共无参数构造函数,请使用它。

  4. 接下来,如果存在私有无参数构造函数并且设置FormatterServices.GetUninitializedObject() 启用后,将使用私有无参数构造函数。

  5. 接下来,如果有一个单个公共参数化构造函数,请使用该构造函数。

  6. 如果不能解决上述问题,Json.NET无法构造该类型的实例。除非有自定义转换器,否则在反序列化期间将抛出异常。

  7. 因此,无参数构造函数优先于参数化构造函数。要强制使用参数化构造函数,请使用[JsonConstructor]标记它们,如上所述:

    public class MyClass3
    {
        private Regex _myRegex;
        private string _myString = null;
    
        public MyClass3() { }
    
        [JsonConstructor]
        // The argument names must match the property names modulo case for Json.NET to deserialize the properties successfully.
        public MyClass3(string myString, Regex myRegex)
        {
            _myString = myString;
            _myRegex = myRegex;
        }
    
        public string MyString { get { return _myString; } }
    
        public Regex MyRegex { get { return _myRegex; } }
    }
    

    或者,您可以删除无参数构造函数,因为它在您的问题的第一个版本中显然不存在。然后对MyClass2进行相同的更改。现在您的类型将成功反序列化。

    请注意,Json.NET有一个ConstructorHandling.AllowNonPublicDefaultConstructor用于序列化Regex

    示例built-in converter