.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
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

上一篇:tinymce 去掉POWERED BY TINY


下一篇:20221.12.31-2022.1.12 学习总结