json 意外状态:对象开始[重复]

h7wcgrx3  于 2022-12-24  发布在  其他
关注(0)|答案(1)|浏览(137)
    • 此问题在此处已有答案**:

Why my dull Newtonsoft.Json deserialization code does not work? [duplicate](1个答案)
13小时前关门了。
我试图序列化一棵树,但我只需要对象数据的一小部分(它是一棵UI树),所以我编写了一个自定义转换器。
转换器只是将读取器和写入器传递给对象

public override void WriteJson(JsonWriter writer, NavTree value, JsonSerializer serializer)
{
    value.SaveAsJson(writer);
}

public override NavTree ReadJson(JsonReader reader, Type objectType, NavTree existingValue, bool hasExistingValue,
    JsonSerializer serializer)
{
    NavTree tree = hasExistingValue ? existingValue : new NavTree();
    tree.LoadFromJson(reader);
    return tree;
}

序列化如下所示

public void SaveAsJson(JsonWriter writer)
{
    SerializableTreeItem root = new (this.GetRoot());
    JObject.FromObject(root).WriteTo(writer);
}

该对象似乎序列化产生的json,类似于

"NavTree": {
    "Id": "All",
    "IsCategory": true,
    "Children": [
      {
        "Id": "https://popularresistance.org/feed/",
        "IsCategory": false,
        "Children": []
      },
      {
        "Id": "https://www.aljazeera.com/xml/rss/all.xml",
        "IsCategory": false,
        "Children": []
      },
      ... more children

反序列化如下所示:

public void LoadFromJson(JsonReader reader)
{
    SerializableTreeItem loaded =
        JsonConvert.DeserializeObject<SerializableTreeItem>((string)reader.Value ?? string.Empty);
    if (loaded == null) return;
    if (this.GetRoot() != null)
    {
        this.GetRoot().Free();
        TreeItem root = this.CreateItem();
        root.SetMetadata(0, RootMetaDataId);
    }

    this.AddItem(loaded, this.GetRoot());
}

尝试访问reader。函数开头的值返回null。尝试访问开头的reader. ReadAsString()将导致:

Newtonsoft.Json.JsonReaderException: Unexpected state: ObjectStart. Path 'NavTree', line 669, position 14.
   at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)
   at Newtonsoft.Json.JsonTextReader.ReadAsString()
   at Porifera.NavTree.LoadFromJson(JsonReader reader)

第669行是上面发布的json的第一行。我以前从来没有做过一个定制的转换器,很明显我把它搞砸了。问题是我做错了什么?json在我看来还不错,我真正需要的是读者提供 * 一些东西 *,我可以重建对象。

e5nqia27

e5nqia271#

您正在将SerializableTreeItem用作NavTreedata transfer object
在编程领域,数据传输对象**(DTO)**是在进程之间传送数据的对象。
您应该做的是重构代码,以分离从JSON转换到DTO以及从DTO转换到NavTree的职责。
首先,修改NavTree以删除对JsonReader或任何其他JSON类型的所有引用:

public partial class NavTree
{
    public void PopulateFromSerializableTreeItem(SerializableTreeItem loaded)
    {
        if (loaded == null) 
            return;
        if (this.GetRoot() != null)
        {
            this.GetRoot().Free();
            TreeItem root = this.CreateItem();
            root.SetMetadata(0, RootMetaDataId);
        }

        this.AddItem(loaded, this.GetRoot());
    }
    
    public SerializableTreeItem ToSerializableTreeItem()
        => new (this.GetRoot());
}

现在,将JsonConverter<NavTree>重写如下:

public class NavTreeConverter : Newtonsoft.Json.JsonConverter<NavTree>
{
    public override void WriteJson(JsonWriter writer, NavTree value, JsonSerializer serializer) =>
        serializer.Serialize(writer, value.ToSerializableTreeItem());

    public override NavTree ReadJson(JsonReader reader, Type objectType, NavTree existingValue, bool hasExistingValue,
        JsonSerializer serializer)
    {
        var loaded = serializer.Deserialize<SerializableTreeItem>(reader);
        // Check for null and return null?  Throw an exception?
        var tree = hasExistingValue ? existingValue : new NavTree();
        tree.PopulateFromSerializableTreeItem(loaded);
        return tree;
    }
}

你应该可以走了。
注:
1.您的JsonReaderException是由以下行引起的:

SerializableTreeItem loaded =
    JsonConvert.DeserializeObject<SerializableTreeItem>((string)reader.Value ?? string.Empty);

JsonReader.Value是当前JSON标记的值,但您使用它时就好像它包含了与SerializableTreeItem对应的整个JSON子树一样,而是使用JsonSerializer.Deserialize<T>(JsonReader)来反序列化当前JSON标记锚定的JSON子树。
1.写的时候,不需要先把你的SerializableTreeItem序列化为一个JObject,然后再写JObject,直接序列化SerializableTreeItem,跳过中间的JObject表示就行了。
1.通过将JSON序列化与DTO转换分离,您将能够更容易地将序列化代码移植到System.Text.Json或任何其他序列化程序(如果您最终选择这样做的话)。

相关问题