1支持忽略循环引用
在 .NET 6 之前,如果 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": []
// }
// ]
// }
2(反)序列化事件通知
在 .NET 6 中,System.Text.Json
暴露了(反)序列化的事件通知接口。
有四个新的接口可以根据你的需要来实现:
IJsonOnDeserialized
IJsonOnDeserializing
IJsonOnSerialized
IJsonOnSerializing
Product invalidProduct = new() { Name = "Name", Test = "Test" };
JsonSerializer.Serialize(invalidProduct);
// The InvalidOperationException is thrownstring invalidJson = "{}";
JsonSerializer.Deserialize<Product>(invalidJson);
// The InvalidOperationException is thrownclass 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 deserializationvoid IJsonOnSerializing.OnSerializing() => Validate(); // Call before serializationprivate void Validate(){if (Name is null){throw new InvalidOperationException("The 'Name' property cannot be 'null'.");}}
}
3支持 Order
属性
以前,序列化顺序是由反射顺序决定的。在 .NET 6 中,System.Text.Json
添加了 JsonPropertyOrderAttribute
特性,它允许控制属性的序列化顺序。
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 Pricepublic string Category { get; set; }[JsonPropertyOrder(1)] // Serialize after other properties that have default orderingpublic decimal Price { get; set; }public string Name { get; set; } // Has default ordering value of 0[JsonPropertyOrder(-1)] // Serialize before other properties that have default orderingpublic int Id { get; set; }
}class A
{public int Test { get; set; }
}// Output:
// {
// "Id": 1,
// "Name": "Surface Pro 7",
// "Price": 550,
// "Category": "Laptops"
// }
4用 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
// }
// ]
// }
5支持 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
下面的 GIF 展示了 IAsyncEnumerable 如何被序列化:
6JSON 和 Stream 互转
在 .NET 6 中,添加了同步方法 Serialize
/Deserialize
的 Stream
重载。
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; }
}
7像 DOM 一样操作 JSON
在 .NET 6 中,提供了处理 in-memory
可写文档对象模型(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); // Textint arrayItem = jNode["Array"][1].GetValue<int>();
Console.WriteLine(arrayItem); // 5// or
arrayItem = jNode["Array"][1].GetValue<int>();
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]}
8收尾
所有的代码示例你都可以在我的 GitHub 上找到:
https://github.com/okyrylchuk/dotnet6_features/tree/main/System.Text.Json%20features
原文:bit.ly/3zma38X
作者:Oleg Kyrylchuk
翻译:精致码农