简体   繁体   English

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

[英]Using Newtonsoft.Json with nested custom classes

I need to serialize some custom objects in order to store information.我需要序列化一些自定义对象以存储信息。 However, I am struggling to deserialize those objects from the serialized JSON string back into their original object forms.但是,我正在努力将这些对象从序列化的 JSON 字符串反序列化回它们的原始对象形式。

The serialized string seems fine:序列化的字符串看起来不错:

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

However, when I reconstruct the original MyClass1 object, the list has one entry as it should but it is filled with nulls instead of the corresnponding data.然而,当我重建原始 MyClass1 对象时,该列表有一个条目,但它填充了空值而不是相应的数据。 Any ideas as to what may be happening?关于可能发生什么的任何想法? Thanks in advance for the brainstorming :)提前感谢您的头脑风暴:)

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

  }

}

Your classes MyClass2 and MyClass3 are read-only.您的类MyClass2MyClass3是只读的。 In order for Json.NET to deserialize a read-only type, you must either provide a custom JsonConverter that manually deserializes and constructs an instance of the type, or provide a parameterized constructor whose argument names match the property names modulo case .为了让 Json.NET 反序列化只读类型,您必须提供一个自定义JsonConverter来手动反序列化并构造该类型的实例,或者提供一个参数化构造函数,其参数名称与属性名称 modulo case 匹配 You have already created the necessary constructors and so are halfway done.您已经创建了必要的构造函数,所以已经完成了一半。

However your types have parameterless constructors as well.但是,您的类型也具有无参数构造函数。 So, which constructor does Json.NET call?那么,Json.NET 调用的是哪个构造函数呢? For a non-enumerable type that is serialized to a JSON object , the following rules apply:对于序列化为JSON object的不可枚举类型,以下规则适用:

  1. If [JsonConstructor] is set on a constructor, use that constructor.如果在构造函数上设置了[JsonConstructor] ,请使用该构造函数。

  2. Next, in full trust only , when MemberSerialization.Fields is applied, or [Serializable] is applied and DefaultContractResolver.IgnoreSerializableAttribute == false , the special method FormatterServices.GetUninitializedObject() is used to allocate the object.接下来, 完全信任的情况下,当应用MemberSerialization.Fields或应用[Serializable]并且DefaultContractResolver.IgnoreSerializableAttribute == false ,特殊方法FormatterServices.GetUninitializedObject()用于分配对象。 None of the type's constructors are called.没有调用任何类型的构造函数。

    (This is an unusual case that does not arise often.) (这是一个不常见的情况,并不经常发生。)

  3. Next, if there is a public parameterless constructor, use it.接下来,如果有公共无参数构造函数,请使用它。

  4. Next, if a private parameterless constructor exists and the setting ConstructorHandling.AllowNonPublicDefaultConstructor is enabled, the private parameterless constructor is used.接下来,如果存在私有无参数构造函数并且启用了ConstructorHandling.AllowNonPublicDefaultConstructor设置,则使用私有无参数构造函数。

  5. Next, if there is a single public parameterized constructor, use that constructor.接下来,如果有一个单一的公共参数的构造函数,使用该构造。

  6. Failing all of the above, Json.NET cannot construct instances of the type.如果上述所有条件都失败,则 Json.NET 无法构造该类型的实例。 An exception will get thrown during deserialization unless a custom converter is available.除非自定义转换器可用,否则反序列化期间将引发异常。

Thus the parameterless constructors take precedence over the parameterized constructors.因此,无参数构造函数优先于参数化构造函数。 To force the parameterized constructors to be used, mark them with [JsonConstructor] as mentioned above:要强制使用参数化构造函数,请使用上面提到的[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; } }
}

Alternatively, you could eliminate the parameterless constructor as it apparently did not exist in the first version of your question.或者,您可以消除无参数构造函数,因为它在问题的第一个版本中显然不存在。 Then make the same change to MyClass2 .然后对MyClass2进行相同的更改。 Now your types will deserialize successfully.现在您的类型将成功反序列化。

Note that Json.NET has a built-in converter for serializing a Regex .请注意, Json.NET 具有用于序列化Regex内置转换器

Sample fiddle .样品小提琴

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM