.NET 6.0 —— Json(TODO)


https://www.zhihu.com/question/449756804

 

作者:醉書生
鏈接:https://www.zhihu.com/question/449756804/answer/2219422015
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

系統.文本.Json

System.Text.Json提供了多種高性能的 API 來處理 JSON 文檔。在過去的幾個版本中,我們添加了新功能,以進一步提高 JSON 處理性能並減輕想要從. 此版本包括在這條道路上的繼續,並且是性能的重大進步,特別是在序列化器源生成器方面。NewtonSoft.Json

JsonSerializer 源代碼生成

注意:應重新編譯使用 .NET 6 RC1 或更早版本的源代碼生成的應用程序。

幾乎所有 .NET 序列化程序的支柱都是反射。反射對於某些場景來說是一項很棒的功能,但不能作為高性能雲原生應用程序(通常(反)序列化和處理大量 JSON 文檔)的基礎。反射是啟動、內存使用和程序集修整的問題

運行時反射的替代方案是編譯時源代碼生成。在 .NET 6 中,我們將一個"https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-source-generator/">新的源生成器作為System.Text.Json. JSON 源生成器可與JsonSerializer多種方式結合使用並可進行配置。

它可以提供以下好處:

  • 減少啟動時間
  • 提高序列化吞吐量
  • 減少私有內存使用
  • 刪除運行時使用和System.ReflectionSystem.Reflection.Emit
  • IL 修整兼容性

默認情況下,JSON 源生成器為給定的可序列化類型發出序列化邏輯。JsonSerializer通過生成Utf8JsonWriter直接使用的源代碼,這提供了比使用現有方法更高的性能。簡而言之,源代碼生成器提供了一種在編譯時為您提供不同實現的方法,以便使運行時體驗更好。

給定一個簡單類型:

namespace Test
{
    internal class JsonMessage
    {
        public string Message { get; set; }
    }
}

源生成器可以配置為為示例JsonMessage類型的實例生成序列化邏輯。請注意,類名JsonContext是任意的。您可以為生成的源使用任何您想要的類名。

using System.Text.Json.Serialization;

namespace Test
{
    [JsonSerializable(typeof(JsonMessage)]
    internal partial class JsonContext : JsonSerializerContext
    {
    }
}

使用此模式的序列化程序調用可能類似於以下示例。此示例提供了可能的最佳性能。

using MemoryStream ms = new();
using Utf8JsonWriter writer = new(ms);

JsonSerializer.Serialize(jsonMessage, JsonContext.Default.JsonMessage);
writer.Flush();

// Writer contains:
// {"Message":"Hello, world!"}

最快和最優化的源代碼生成模式——基於Utf8JsonWriter——目前僅可用於序列化。Utf8JsonReader根據您的反饋,未來可能會提供類似的反序列化支持——基於——。

源生成器還發出類型元數據初始化邏輯,這也有利於反序列化。要反序列化JsonMessage使用預生成類型元數據的實例,您可以執行以下操作:

作者:醉書生
鏈接:https://www.zhihu.com/question/449756804/answer/2219422015
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

 

JsonSerializer.Deserialize(json, JsonContext.Default.JsonMessage);

JsonSerializer 支持 IAsyncEnumerable

現在,可以(反)序列化JSON陣列IAsyncEnumerable<T>與。以下示例使用流作為數據的任何異步源的表示。源可以是本地機器上的文件,也可以是數據庫查詢或 Web 服務 API 調用的結果。System.Text.Json

JsonSerializer.SerializeAsync已更新以識別IAsyncEnumerable值並提供特殊處理。

using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;

static async IAsyncEnumerable<int> PrintNumbers(int n)
{
    for (int i = 0; i < n; i++) yield return i;
}

using Stream stream = Console.OpenStandardOutput();
var data = new { Data = PrintNumbers(3) };
await JsonSerializer.SerializeAsync(stream, data); // prints {"Data":[0,1,2]}

IAsyncEnumerable值僅支持使用異步序列化方法。嘗試使用同步方法進行序列化將導致NotSupportedException拋出異常。

流式反序列化需要一個新的 API 返回. 我們為此目的添加了該方法,您可以在以下示例中看到。IAsyncEnumerable<T>JsonSerializer.DeserializeAsyncEnumerable

using System;
using System.IO;
using System.Text;
using System.Text.Json;

var stream = new MemoryStream(Encoding.UTF8.GetBytes("[0,1,2,3,4]"));
await foreach (int item in JsonSerializer.DeserializeAsyncEnumerable<int>(stream))
{
    Console.WriteLine(item);
}

此示例將按需反序列化元素,並且在使用特別大的數據流時非常有用。它只支持從根級 JSON 數組中讀取,盡管將來可能會根據反饋放寬。

現有DeserializeAsync方法名義上支持,但在其非流式方法簽名的范圍內。它必須將最終結果作為單個值返回,如下例所示。IAsyncEnumerable<T>

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.Json;

var stream = new MemoryStream(Encoding.UTF8.GetBytes(@"{""Data"":[0,1,2,3,4]}"));
var result = await JsonSerializer.DeserializeAsync<MyPoco>(stream);
await foreach (int item in result.Data)
{
    Console.WriteLine(item);
}

public class MyPoco
{
    public IAsyncEnumerable<int> Data { get; set; }
}

在此示例中,反序列化器將IAsyncEnumerable在返回反序列化對象之前緩沖內存中的所有內容。這是因為反序列化器需要在返回結果之前消耗整個 JSON 值。

作者:醉書生
鏈接:https://www.zhihu.com/question/449756804/answer/2219422015
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

System.Text.Json:可寫 DOM 功能

寫JSON DOM功能增加了一個新的簡單的,高性能的編程模型的。這個新的 API 很有吸引力,因為它避免了需要強類型的序列化契約,並且與現有類型相比,DOM 是可變的。System.Text.JsonJsonDocument

這個新的 API 有以下好處:

  • 在不可能或不希望使用POCO類型的情況下,或者當 JSON 模式不固定且必須檢查時,序列化的輕量級替代方案。
  • 允許對大樹的子集進行有效修改。例如,可以高效地導航到大型 JSON 樹的子部分並從該子部分讀取數組或反序列化 POCO。LINQ 也可以與它一起使用。

以下示例演示了新的編程模型。

    // Parse a JSON object
    JsonNode jNode = JsonNode.Parse("{"MyProperty":42}");
    int value = (int)jNode["MyProperty"];
    Debug.Assert(value == 42);
    // or
    value = jNode["MyProperty"].GetValue<int>();
    Debug.Assert(value == 42);

    // Parse a JSON array
    jNode = JsonNode.Parse("[10,11,12]");
    value = (int)jNode[1];
    Debug.Assert(value == 11);
    // or
    value = jNode[1].GetValue<int>();
    Debug.Assert(value == 11);

    // Create a new JsonObject using object initializers and array params
    var jObject = new JsonObject
    {
        ["MyChildObject"] = new JsonObject
        {
            ["MyProperty"] = "Hello",
            ["MyArray"] = new JsonArray(10, 11, 12)
        }
    };

    // Obtain the JSON from the new JsonObject
    string json = jObject.ToJsonString();
    Console.WriteLine(json); // {"MyChildObject":{"MyProperty":"Hello","MyArray":[10,11,12]}}

    // Indexers for property names and array elements are supported and can be chained
    Debug.Assert(jObject["MyChildObject"]["MyArray"][1].GetValue<int>() == 11);

ReferenceHandler.IgnoreCycles



JsonSerializer(System.Text.Json)現在支持在序列化對象圖時忽略循環的能力。該選項的行為與 Newtonsoft.Json 相似。一個主要區別是 System.Text.Json 實現用JSON 標記替換引用循環,而不是忽略對象引用。ReferenceHandler.IgnoreCyclesReferenceLoopHandling.Ignorenull

您可以在以下示例中看到 的行為。在這種情況下,屬性被序列化,因為它否則會創建一個循環。ReferenceHandler.IgnoreCyclesNextnull

class Node
{
    public string Description { get; set; }
    public object Next { get; set; }
}

void Test()
{
    var node = new Node { Description = "Node 1" };
    node.Next = node;

    var opts = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.IgnoreCycles };

    string json = JsonSerializer.Serialize(node, opts);
    Console.WriteLine(json); // Prints {"Description":"Node 1","Next":null}
}

 

 

作者:醉書生
鏈接:https://www.zhihu.com/question/449756804/answer/2219422015
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM