System.Text.Json Utf8JsonReader 正在读取数组值两次

问题描述 投票:0回答:1

我正在尝试使用 Utf8JsonReader 进行反序列化,因为它可以轻松制作,但我需要进行自定义反序列化。 当我尝试反序列化一个包含对象的数组时,它会读取它两次。

在此输入图片描述

我没有找到很多如何使用 Utf8JsonReader 的信息,所以也许我做的这一切都不正确。

这是我的反序列化代码:

public Map? ReadYaml(string json)
{
    JsonReaderOptions options = new() { AllowTrailingCommas = true, CommentHandling = JsonCommentHandling.Skip };
    Utf8JsonReader reader = new(System.Text.Encoding.UTF8.GetBytes(json), options);

    Map map = new();

    while (reader.Read())
    {
        switch (reader.TokenType)
        {
            case JsonTokenType.PropertyName:
                if (reader.ValueTextEquals("Map name"))
                {
                    reader.Read();

                    map = new(reader.GetString());
                }
                if (reader.ValueTextEquals("Entities"))
                {
                    reader.Read();

                    if (reader.TokenType == JsonTokenType.StartArray)
                    {
                        while (reader.Read())
                        {
                            if (reader.TokenType == JsonTokenType.EndArray)
                                break;

                            if (reader.TokenType == JsonTokenType.StartObject)
                            {
                                while (reader.Read())
                                {
                                    if (reader.TokenType == JsonTokenType.EndObject)
                                        break;

                                    if (reader.TokenType == JsonTokenType.PropertyName)
                                    {
                                        reader.Read();
                                        if (reader.TokenType == JsonTokenType.String)
                                        {
                                            var str = reader.GetString();
                                            if (str != null)
                                            {
                                                Debug.Log(str);
                                            }
                                        }
                                    }
                                }
                            }
                            else
                            {
                                break;
                            }
                        }
                    }
                }
                break;
        }
    }
    return map;
}

这是我要反序列化的 JSON 文件:


{
  "Map name": "NewMap",
  "Entities": [
    {
      "Name": "Entity",
      "Active": "True",
      "GUID": "f06ed7d3-f1b3-4cfd-a623-a7ceb17dbced"
    },
    {
      "Name": "Entity #1",
      "Active": "True",
      "GUID": "03788f46-e430-4882-a097-e860d2c7aed5"
    }
  ],
  "Entity components": [
    {
      "Component type": "ExtremeEngine.Transform",
      "Component data": [
        {
          "Position": null,
          "Rotation": null,
          "Scale": null,
          "Entity": "f06ed7d3-f1b3-4cfd-a623-a7ceb17dbced",
          "GUIHeaderIsOpened": "True",
          "Enabled": "True",
          "GUID": "95dea154-6f00-41b0-bdec-fe78cca589c3"
        }
      ]
    },
    {
      "Component type": "ExtremeEngine.Transform",
      "Component data": [
        {
          "Position": null,
          "Rotation": null,
          "Scale": null,
          "Entity": "03788f46-e430-4882-a097-e860d2c7aed5",
          "GUIHeaderIsOpened": "True",
          "Enabled": "True",
          "GUID": "d92b131a-a82f-487f-b1c1-25ff13496284"
        }
      ]
    }
  ]
}
c# json system.text.json
1个回答
0
投票

Utf8JsonReader
很难直接使用,因为它被设计用于从 UTF8 字节范围序列(通常从管道生成)中异步读取 JSON 令牌。

与直接与读者合作相比,通过设计适当的 DTO 或数据模型,然后使用 JsonSerializer.Deserialize()

 对其进行反序列化,
反序列化 JSON 会容易得多。

使用https://json2csharp.com/如何从 JSON 字符串自动生成 C# 类文件中提到的工具之一),我生成了以下数据模型:

public class Map
{
    // https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json/immutability
    // Important: System.Text.Json requires that the constructor parameter names are the same as the corresponding property names, ignoring differences in case.
    [JsonConstructor]
    public Map(string mapname) => this.Mapname = mapname;
    public Map() : this("") { }
    
    [JsonPropertyName("Map name")]
    public string Mapname { get; }

    [JsonPropertyName("Entities")]
    public List<Entity> Entities { get; set; }

    [JsonPropertyName("Entity components")]
    public List<EntityComponent> Entitycomponents { get; set; }
}

public class ComponentDatum
{
    [JsonPropertyName("Position")]
    public object Position { get; set; } // TODO: update with the correct type

    [JsonPropertyName("Rotation")]
    public object Rotation { get; set; } // TODO: update with the correct type

    [JsonPropertyName("Scale")]
    public object Scale { get; set; } // TODO: update with the correct type

    [JsonPropertyName("Entity")]
    public string Entity { get; set; }

    [JsonPropertyName("GUIHeaderIsOpened")]
    public string GUIHeaderIsOpened { get; set; }

    [JsonPropertyName("Enabled")]
    public string Enabled { get; set; }

    [JsonPropertyName("GUID")]
    public Guid GUID { get; set; } // Changed from string to Guid
}

public class Entity
{
    [JsonPropertyName("Name")]
    public string Name { get; set; }

    [JsonPropertyName("Active")]
    public string Active { get; set; }

    [JsonPropertyName("GUID")]
    public Guid GUID { get; set; } // Changed from string to Guid
}

public class EntityComponent
{
    [JsonPropertyName("Component type")]
    public string Componenttype { get; set; }

    [JsonPropertyName("Component data")]
    public List<ComponentDatum> Componentdata { get; set; }
}

生成模型后,我做了两个小改动:

  • 我为

    Mapname
    引入了参数化构造函数。

  • 我将

    GUID
    属性的类型从
    string
    更改为
    Guid

使用该模型,您的 JSON 可以从字符串或文件中反序列化,如下所示:

static JsonSerializerOptions DefaultOptions { get; } = new() { AllowTrailingCommas = true, ReadCommentHandling = JsonCommentHandling.Skip };

public Map? ReadYamlFromFile(string filePath)
{
    using (var stream = File.OpenRead(filePath))
        return JsonSerializer.Deserialize<Map>(stream, DefaultOptions);
}

public Map? ReadYaml(string json) =>
    JsonSerializer.Deserialize<Map>(json, DefaultOptions);

演示小提琴这里

© www.soinside.com 2019 - 2024. All rights reserved.