我正在尝试使用 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"
}
]
}
]
}
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);
演示小提琴这里。