Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/311.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 无参数构造函数的自引用类层次结构的序列化/反序列化_C#_Json_Json.net_Deserialization_Hierarchy - Fatal编程技术网

C# 无参数构造函数的自引用类层次结构的序列化/反序列化

C# 无参数构造函数的自引用类层次结构的序列化/反序列化,c#,json,json.net,deserialization,hierarchy,C#,Json,Json.net,Deserialization,Hierarchy,我有一个分层类ConversationModel,需要序列化/反序列化到JSON 请注意,ConversationNode类没有无参数构造函数。唯一的非默认构造函数也标记为内部。所有类属性都是get only。这是为了使类保持不变、无状态和防白痴 using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Newtonsoft.Json; public class Co

我有一个分层类
ConversationModel
,需要序列化/反序列化到
JSON

请注意,
ConversationNode
类没有无参数构造函数。唯一的
非默认
构造函数也标记为
内部
。所有类属性都是
get only
。这是为了使类保持不变、无状态和防白痴

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using Newtonsoft.Json;

public class ConversationModel
{
    public ConversationNode Node { get; }

    public ConversationModel ()
        => this.Node = new ConversationNode(this, null);

    public static JsonSerializerSettings JsonSerializerSettings
        => new JsonSerializerSettings
        {
            Formatting = Formatting.Indented,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            PreserveReferencesHandling = PreserveReferencesHandling.All,
            TypeNameAssemblyFormatHandling = TypeNameAssemblyFormatHandling.Full,
            Converters = new [] { new ConversationModelJsonConverter(), },
        };

    public string Serialize ()
        => JsonConvert.SerializeObject(this, this.GetType(), ConversationModel.JsonSerializerSettings);

    public static ConversationModel FromJson (string json)
        => JsonConvert.DeserializeObject<ConversationModel>(json, ConversationModel.JsonSerializerSettings);
}

public class ConversationNode
{
    public ConversationModel Model { get; }
    public ConversationNode Parent { get; }
    public ConversationNodeList Nodes { get; }

    internal ConversationNode (ConversationModel model, ConversationNode parent)
    {
        this.Model = model ?? throw (new ArgumentNullException(nameof(model)));
        this.Parent = parent ?? throw (new ArgumentNullException(nameof(parent)));
        this.Nodes = new ConversationNodeList (model, parent);
    }
}

public class ConversationNodeList:
    List<ConversationNode>
{
    public ConversationModel Model { get; }
    public ConversationNode Parent { get; }

    public ConversationNodeList (ConversationModel model, ConversationNode parent)
    {
        this.Model = model;
        this.Parent = parent;
    }
}
问题是:

  • 是否可以编写一个自定义的
    JsonConverter
    来实现这一点?如果是,怎么做
  • 有没有比实现自定义的
    JsonConverter
    更简单的方法

  • “当然,JsonSerializer需要一个公共的、默认的、无参数的构造函数”——事实并非如此。它可以使用非公共构造函数,也可以使用非无参数构造函数(就像您当前拥有的构造函数)。我用
    [jsonstructor]
    属性标记了
    内部
    构造函数,它抛出了一个
    JsonSerializationException
    ,尽管是在层次结构的某个地方。换句话说,它可以调用构造函数,但在某些情况下会失败。反序列化的JSON是使用具有相同设置的相同序列化程序生成的。奇怪。我认为您需要提供可复制的示例,因为使用当前代码,可以按原样序列化和反序列化basic
    new ConversationModel()
    ,而无需修改(更改
    ConversationNode
    以允许空父级除外).
    PreserveReferencesHandling
    被记录为不使用非默认构造函数。请参阅:以及:当通过非默认构造函数设置值时,无法保留引用。对于非默认构造函数,必须在父值之前创建子值,以便将其传递到构造函数中,从而无法跟踪引用。也就是说,Json.NET通常支持参数化构造函数。有关选择适当构造函数的算法,请参见。
    public sealed class ConversationModelJsonConverter:
        JsonConverter<ConversationModel>
    {
        public override void WriteJson (JsonWriter writer, [AllowNull] ConversationModel value, JsonSerializer serializer)
        {
            // ???
        }
    
        public override ConversationModel ReadJson (JsonReader reader, Type objectType, [AllowNull] ConversationModel existingValue, bool hasExistingValue, JsonSerializer serializer)
        {
            // ???
            return (null);
        }
    }