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
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。