Объектно-внедренный словарь JSON.net становится NULL - PullRequest
0 голосов
/ 06 февраля 2019

У меня есть следующий объект 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 голосов
/ 06 февраля 2019

Ни одно из свойств не установлено, потому что их установщики 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; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...