• [译] Seven System.Text.Json features in the .NET 6


    介绍

    接下来我将给大家重点介绍一下.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

    公众号

  • 相关阅读:
    从app加载页面说开去
    NSLog打印各种类型数据的方法
    17个常用代码整理
    成为优秀程序员的10点建议
    iOS常用第三方类库
    iPhone开发如何捕获提交异常日志
    IOS 关于四舍五入的神器NSDecimalNumber
    面向对象与面向过程的一点思考
    程序员,你会为谁卖命?
    关于面向对象的一点思考
  • 原文地址:https://www.cnblogs.com/MrChuJiu/p/15802598.html
Copyright © 2020-2023  润新知