[譯] Seven System.Text.Json features in the .NET 6
阿新 • • 發佈:2022-01-14
介紹
接下來我將給大家重點介紹一下.Net 6 之後的一些新的變更,文章都是來自於外國大佬的文章,我這邊進行一個翻譯,並加上一些自己的理解和解釋。
源作者連結:https://blog.okyrylchuk.dev/system-text-json-features-in-the-dotnet-6
正文
忽略迴圈引用
在 .NET 5 中,您可以使用 System.Text.Json 保留迴圈引用的引用。但你不能忽視它們。如果檢測到迴圈引用,則丟擲JsonException 。在 .NET 6 中,您可以忽略它們。
Category dotnet = new() { Name = ".NET 6", }; Category systemTextJson = new() { Name = "System.Text.Json", Parent = dotnet }; dotnet.Children.Add(systemTextJson); JsonSerializerOptions options = new() { ReferenceHandler = ReferenceHandler.IgnoreCycles, WriteIndented = true }; string dotnetJson = JsonSerializer.Serialize(dotnet, options); Console.WriteLine($"{dotnetJson}"); public class Category { public string Name { get; set; } public Category Parent { get; set; } public List<Category> Children { get; set; } = new(); } // Output: // { // "Name": ".NET 6", // "Parent": null, // "Children": [ // { // "Name": "System.Text.Json", // "Parent": null, // "Children": [] // } // ] // }
(反)序列化通知
在 .NET 6 中,System.Text.Json 公開了(反)序列化的通知。
有四個新介面可以根據您的需要實現:
- IJsonOnDeserialized
- IJsonOnDeserializing
- IJsonOnSerialized
- IJsonOnSerializing
Product invalidProduct = new() { Name = "Name", Test = "Test" }; JsonSerializer.Serialize(invalidProduct); // The InvalidOperationException is thrown string invalidJson = "{}"; JsonSerializer.Deserialize<Product>(invalidJson); // The InvalidOperationException is thrown class Product : IJsonOnDeserialized, IJsonOnSerializing, IJsonOnSerialized { public string Name { get; set; } public string Test { get; set; } public void OnSerialized() { throw new NotImplementedException(); } void IJsonOnDeserialized.OnDeserialized() => Validate(); // Call after deserialization void IJsonOnSerializing.OnSerializing() => Validate(); // Call before serialization private void Validate() { if (Name is null) { throw new InvalidOperationException("The 'Name' property cannot be 'null'."); } } }
屬性的序列化順序
Product product = new() { Id = 1, Name = "Surface Pro 7", Price = 550, Category = "Laptops" }; JsonSerializerOptions options = new() { WriteIndented = true }; string json = JsonSerializer.Serialize(product, options); Console.WriteLine(json); class Product : A { [JsonPropertyOrder(2)] // Serialize after Price public string Category { get; set; } [JsonPropertyOrder(1)] // Serialize after other properties that have default ordering public decimal Price { get; set; } public string Name { get; set; } // Has default ordering value of 0 [JsonPropertyOrder(-1)] // Serialize before other properties that have default ordering public int Id { get; set; } } class A { public int Test { get; set; } } // Output: // { // "Id": 1, // "Name": "Surface Pro 7", // "Price": 550, // "Category": "Laptops" // }
使用 Utf8JsonWriter 編寫原始 JSON
.NET 6 引入了使用 System.Text.Json.Utf8JsonWriter 編寫原始 JSON 的可能性。
在您需要時很有幫助:
將現有 JSON 包含在新 JSON 中
以不同於預設格式的方式格式化值
JsonWriterOptions writerOptions = new() { Indented = true, };
using MemoryStream stream = new();
using Utf8JsonWriter writer = new(stream, writerOptions);
writer.WriteStartObject();
writer.WriteStartArray("customJsonFormatting");
foreach (double result in new double[] { 10.2, 10 })
{
writer.WriteStartObject();
writer.WritePropertyName("value");
writer.WriteRawValue(FormatNumberValue(result), skipInputValidation: true);
writer.WriteEndObject();
}
writer.WriteEndArray();
writer.WriteEndObject();
writer.Flush();
string json = Encoding.UTF8.GetString(stream.ToArray());
Console.WriteLine(json);
static string FormatNumberValue(double numberValue)
{
return numberValue == Convert.ToInt32(numberValue)
? numberValue.ToString() + ".0"
: numberValue.ToString();
}
// Output:
// {
// "customJsonFormatting": [
// {
// "value": 10.2
// },
// {
// "value": 10.0
// }
// ]
// }
IAsyncEnumerable 支援
在 .NET 6 中,System.Text.Json 支援IAsyncEnumerable。IAsyncEnumerable的序列化將其轉換為陣列。對於根級 JSON 陣列的反序列化,添加了DeserializeAsyncEnumerable方法。
static async IAsyncEnumerable<int> GetNumbersAsync(int n)
{
for (int i = 0; i < n; i++)
{
await Task.Delay(1000);
yield return i;
}
}
// Serialization using IAsyncEnumerable
JsonSerializerOptions options = new() { WriteIndented = true };
using Stream outputStream = Console.OpenStandardOutput();
var data = new { Data = GetNumbersAsync(5) };
await JsonSerializer.SerializeAsync(outputStream, data, options);
// Output:
// {
// "Data": [
// 0,
// 1,
// 2,
// 3,
// 4
// ]
// }
// Deserialization using IAsyncEnumerable
using MemoryStream memoryStream = new(Encoding.UTF8.GetBytes("[0,1,2,3,4]"));
// Wraps the UTF-8 encoded text into an IAsyncEnumerable<T> that can be used to deserialize root-level JSON arrays in a streaming manner.
await foreach (int item in JsonSerializer.DeserializeAsyncEnumerable<int>(memoryStream))
{
Console.WriteLine(item);
}
// Output:
// 0
// 1
// 2
// 3
// 4
(反)將 JSON 資料序列化到/從流中
在 .NET 6 中,為同步方法 Serialize/Deserialize 添加了流的過載。
string json = "{\"Value\":\"Deserialized from stream\"}";
byte[] bytes = Encoding.UTF8.GetBytes(json);
// Deserialize from stream
using MemoryStream ms = new MemoryStream(bytes);
Example desializedExample = JsonSerializer.Deserialize<Example>(ms);
Console.WriteLine(desializedExample.Value);
// Output: Deserialized from stream
// ==================================================================
// Serialize to stream
JsonSerializerOptions options = new() { WriteIndented = true };
using Stream outputStream = Console.OpenStandardOutput();
Example exampleToSerialize = new() { Value = "Serialized from stream" };
JsonSerializer.Serialize<Example>(outputStream, exampleToSerialize, options);
// Output:
// {
// "Value": "Serialized from stream"
// }
class Example
{
public string Value { get; set; }
}
像 DOM 一樣使用 JSON
.NET 6 提供了用於處理記憶體中可寫文件物件模型 (DOM) 的型別,以便隨機訪問結構化資料檢視中的 JSON 元素。
新型別:
- JsonArray
- JsonNode
- JsonObject
- JsonValue
// Parse a JSON object
JsonNode jNode = JsonNode.Parse("{\"Value\":\"Text\",\"Array\":[1,5,13,17,2]}");
string value = (string)jNode["Value"];
Console.WriteLine(value); // Text
// or
value = jNode["Value"].GetValue<string>();
Console.WriteLine(value); // Text
int arrayItem = jNode["Array"][1].GetValue<int>();
Console.WriteLine(arrayItem); // 5
// or
arrayItem = (int)jNode["Array"][1];
Console.WriteLine(arrayItem); // 5
// Create a new JsonObject
var jObject = new JsonObject
{
["Value"] = "Text",
["Array"] = new JsonArray(1, 5, 13, 17, 2)
};
Console.WriteLine(jObject["Value"].GetValue<string>()); // Text
Console.WriteLine(jObject["Array"][1].GetValue<int>()); // 5
// Converts the current instance to string in JSON format
string json = jObject.ToJsonString();
Console.WriteLine(json); // {"Value":"Text","Array":[1,5,13,17,2]}
結語
聯絡作者:加群:867095512 @MrChuJiu