JSON.net对象嵌入式词典变为NULL

时间:2019-02-06 09:44:18

标签: c# json json.net deserialization json-deserialization

我有以下C#对象:

public abstract partial class ClientTreeNode {
    public int ID { get; internal set; }
    public string Question { get; internal set; }
    public List<ClientTreeNode> Children { get; internal set; }
    public QuestionCategories Category { get; internal set; }
    public Dictionary<object, List<int>> AnswerNodes { get; internal set; }

    public string Type => GetType().Name.Replace("TreeNode", "").FirstCharacterToLower();

    public string CategoryText {
        get {
            switch (Category) {
                case QuestionCategories.VisualInspection:
                    return "Sichtprüfung";
                case QuestionCategories.MechanicalInspection:
                    return "Mechanische Prüfung";
                case QuestionCategories.ElectricalInspection:
                    return "Elektrische Prüfung";
                default:
                    return "Fehler";
            }
        }
    }

    public abstract AnswerResult Answer(JObject data);

    internal static ClientTreeNode FromDatabase(int ID, out int TotalChildNodes) {
        // ....
    }

    internal static int SumUpChildNodes(List<int> nodeIDs) {
        using (var db = new DatabaseEntities()) {
            return db.TreeNodes
                .Where(tn => nodeIDs.Contains(tn.ID))
                .Sum(tn => tn.TotalChildNodes);
        }
    }

    [JsonConverter(typeof(StringEnumConverter), true)]
    public enum QuestionCategories {
        VisualInspection,
        MechanicalInspection,
        ElectricalInspection
    }
}

public class YesNoTreeNode : ClientTreeNode {
    public bool Result { get; internal set; }

    public override AnswerResult Answer(JObject data) {
        if (data["result"].Type != JTokenType.Boolean)
            throw new ArgumentException("The provided answer was invalid.");

        Result = data["result"].Value<bool>();
        Children = new List<ClientTreeNode>();

        foreach (var childNodeID in AnswerNodes[Result])
            Children.Add(FromDatabase(childNodeID, out _));

        return new AnswerResult(SumUpChildNodes(AnswerNodes[!Result]), Children);
    }
}

JSON文件如下所示:

{"AnswerNodes":{"True":[4],"False":[5]}}

有时候,它可能会更高级。但这并非在所有情况下都是强制性的:

{"Result":false,"ID":0,"Question":null,"Children":null,"Category":"visualInspection","AnswerNodes":{"True":[4],"False":[5]},"Type":"yesNo","CategoryText":"Sichtprüfung"}

当我尝试使用以下代码对其进行解码时,除AnswerNodes字典外,所有值都被填充。总是变为空:

JsonConvert.DeserializeObject<YesNoTreeNode>(node.NodeOptionsJSON);

// This is a workaround:
if (ret.AnswerNodes is null)
    ret.AnswerNodes = JObject.Parse(node.NodeOptionsJSON)["AnswerNodes"].ToObject<Dictionary<object, List<int>>>();

即使在以下测试方案中,它也不起作用。因此,我可以除外,这是由于JSON代码格式错误造成的。

ret = loadFromJSON ? JsonConvert.DeserializeObject<YesNoTreeNode>(node.NodeOptionsJSON) : new YesNoTreeNode();

// At this point, ret.AnswerNodes is null

ret.AnswerNodes = new Dictionary<object, List<int>>();
ret.AnswerNodes.Add(1, new List<int>() { 4 });
ret.AnswerNodes.Add(2, new List<int>() { 5 });

var test = JsonConvert.SerializeObject(ret);
var test2 = JsonConvert.DeserializeObject<YesNoTreeNode>(test);

首先有没有办法使DeserializeObject方法正确解码对象?

1 个答案:

答案 0 :(得分:2)

未设置任何属性,因为其设置器为internal set;。这意味着它们对其他程序集(例如Json.NET)不可见。

Linqpad中的以下代码:

public enum QuestionCategories 
{
    None,
    visualInspection
}

public abstract partial class ClientTreeNode {
    public int ID { get; internal set; }
    public string Question { get; internal set; }
    public List<ClientTreeNode> Children { get; internal set; }
    public QuestionCategories Category { get; internal set; }
    public Dictionary<object, int[]> AnswerNodes { get; internal set; }
}

public class YesNoTreeNode : ClientTreeNode {
    public bool Result { get; internal set; }

}

void Main()
{
    var json="{'Result':false,'ID':0,'Question':null,'Children':null,'Category':'visualInspection','AnswerNodes':{'True':[4],'False':[5]},'Type':'yesNo','CategoryText':'Sichtprüfung'}";
    var obj=JsonConvert.DeserializeObject<YesNoTreeNode>(json);
    JsonConvert.SerializeObject(obj).Dump();
}

产生:

{ "Result":false,
  "ID":0,
  "Question":null,
  "Children":null,
  "Category":0,
  "AnswerNodes":null
}

删除internal会产生预期的结果:

{ "Result":false,
  "ID":0,"Question":null,"Children":null,"Category":1,
  "AnswerNodes":{"True":[4],"False":[5]}
}

默认情况下,Json.NET仅设置公共属性。

如果属性用JsonProperty属性标记,则可以使用内部设置器,甚至私有设置器:

public abstract partial class ClientTreeNode {

    [JsonProperty]
    public int ID { get;  private set; }

    [JsonProperty]
    public string Question { get;  private set; }

    [JsonProperty]
    public List<ClientTreeNode> Children { get;  private set; }

    [JsonProperty]
    public QuestionCategories Category { get;  private set; }

    [JsonProperty]
    public Dictionary<object, int[]> AnswerNodes { get;  private set; }
}