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

C# 将Newtonsoft.Json与嵌套的自定义类一起使用,c#,json,serialization,json.net,C#,Json,Serialization,Json.net,我需要序列化一些自定义对象以存储信息。但是,我正在努力将这些对象从序列化的JSON字符串反序列化回其原始对象形式 序列化字符串似乎很好: [ { "MyStringArray": [ "stringInput1", "stringInput2" ], "MyCharArray": [ "a", "b", "c", "." ], "MyString": "dummy", "M

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

序列化字符串似乎很好:

[
  {
    "MyStringArray": [
      "stringInput1",
      "stringInput2"
    ],
    "MyCharArray": [
      "a",
      "b",
      "c",
      "."
    ],
    "MyString": "dummy",
    "MyClass3Object": [
      {
        "MyString": "ListInput1"
      },
      {
        "MyString": "ListInput2"
      }
    ]
  }
]
但是,当我重建原始MyClass1对象时,列表中应有一个条目,但它是用空值填充的,而不是相应的数据。对可能发生的事情有什么想法吗?提前感谢您的头脑风暴:)

使用系统;
使用System.Collections.Generic;
使用Newtonsoft.Json;
使用System.IO;
使用System.Text.RegularExpressions;
命名空间JsonTesting
{
班级计划
{
静态void Main(字符串[]参数)
{
MyClass1 c1=新的MyClass1();
c1.AddInfo();
string to JSONString=JsonConvert.SerializeObject(c1,Formatting.Indented,
新的JsonSerializerSettings{DefaultValueHandling=DefaultValueHandling.Include});
writealText(@“C:\temp\dumpJsonText.txt”,toJsonString);
MyClass1 fromJson=JsonConvert.DeserializeObject(toJsonString);
Console.ReadLine();
}
}
公共类MyClass1:列表{
公共MyClass1(){}
public void AddInfo(){
Add(新MyClass2(新字符串[]{“stringInput1”,“stringInput2”},
新字符[]{a',b',c','.'.},
“哑巴”,
new List(){new MyClass3(“ListInput1”,new Regex(@“[A-Z]”),new MyClass3(“ListInput2”,new Regex(@“[0-9]”))}
));
}
}
公共类MyClass2
{
私有字符串[]\u myStringArray=null;
private char[]\u myCharArray=null;
私有字符串_myString=null;
私有列表_myClass3Object=null;
公共MyClass2(){}
public MyClass2(字符串[]myStringArray,字符[]myCharArray,字符串myString,列表myClass3Object)
{
_myStringArray=myStringArray;
_myCharArray=myCharArray;
_myString=myString;
_myClass3Object=myClass3Object;
}
公共字符串[]MyStringArray{get{return\u MyStringArray;}}
public char[]MyCharArray{get{return\u MyCharArray;}}
公共字符串MyString{get{return\u MyString;}}
公共列表MyClass3Object{get{return}
}
公共类MyClass3{
私人Regex_myRegex;
私有字符串_myString=null;
公共MyClass3(){}
公共MyClass3(字符串myString,Regex-myRegex){
_myString=myString;
_myRegex=myRegex;
}
公共字符串MyString{get{return\u MyString;}}
}
}

您的类
MyClass2
MyClass3
是只读的。为了让Json.NET对只读类型进行反序列化,必须提供手动反序列化并构造该类型实例的构造函数,或者提供参数化构造函数,其参数名称与属性名称的大小写模匹配。您已经创建了必要的构造函数,因此完成了一半

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

  • 如果在构造函数上设置了,则使用该构造函数

  • 接下来,在中,当应用
    成员序列化.Fields
    或应用
    [Serializable]
    时,使用特殊方法分配对象。没有调用类型的构造函数

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

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

  • 接下来,如果存在私有无参数构造函数,则 如果启用,则使用专用无参数构造函数

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

  • 如果上述所有操作失败,Json.NET将无法构造该类型的实例。除非自定义转换器可用,否则在反序列化过程中将引发异常

  • 因此,无参数构造函数优先于参数化构造函数。要强制使用参数化构造函数,请使用上面提到的
    [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有一个用于序列化
    Regex
    的函数


    示例。

    您没有任何公共空构造函数,因此它不知道如何创建嵌套对象。我在所有3个类中都有空构造函数。我只是忘了在这里添加它。你在问为什么非常特定的代码行为不正确,然后你发布了伪代码。我完全按照我的项目中的方式编写了代码,只是更改了名称和推荐了不相关的方法。提供了一个重现问题的方法,以便可以得到更好的答案。我在MyClass2和MyClass3中添加了[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; } }
    }