【C# 序列化】 Utf8JsonReader和Utf8JsonWriter

简介

【C# 序列化】 ReadOnlySequence<T>

JsonTokenType枚举:定义组成JSON文本的各种JSON标志。例如startArray 表示 【 [】,  endArray表示【 ]】comment表示【//】,属性名表示PropertyName

ref struct 是仅在堆栈上的值类型使用限制如下:  

  •      表现一个顺序结构的布局;(译注:可以理解为连续内存)
  •     只能在堆栈上使用。即用作方法参数和局部变量;
  •     不能用来声明类或非 ref结构的静态或实例成员;
  •     不能被本地函数捕获或lambda表达式的方法参数;
  •     不能动态绑定、装箱\拆箱。
  •     不能在异步方法、迭代器、数组、类型参数(泛型)中使用

ref struct也被称为嵌入式引用。

ReadOnlySequence<Byte>:序列(英語:Sequences)在数学中是指被排成一列的对象或事件;例如,(C,Y,R)是一个字母的序列:顺序是C第一,Y第二,R第三。序列可以是有限的(就像前面这个例子),也可以是无限的,就像所有正偶数的序列(2,4,6,...)。有限序列包含空序列(),它没有元素。序列中的元素也称为项,项的个数(可能是无限的)称为序列的长度。序列写作(a1,a2, ...)。简单起见,也可以用符号(an)。有限的序列称为列表(lists)。有限的字符串序列称为字符串(string)。无限的序列称为字符串流(stream)。
ReadOnlySequenceSegment<T>:

ReadOnlySpan<Byte>:高性能内存空间读取数据结构。支持数组、list、字符窜。BytesConsumed:获取到目前为止Utf8JsonReader实例消耗的总字节数。

Utf8JsonReader

属性

CurrentDepth:获取当前标记的深度。现状后获取Utf8JsonReader的当前状态,并将其传递给Utf8JsonReader构造函数。
HasValueSequence:获取一个值,该值指示要使用哪个value属性来获取令牌值。
IsFinalBlock:获取Utf8JsonReader的这个实例的模式,该模式指示是否提供了所有的JSON数据,或者还有更多的数据。位置在提供的UTF-8编码的输入ReadOnlySequence中获取当前的SequencePosition;如果Utf8JsonReader结构体是用ReadOnlySpan构造的,则获取默认的SequencePosition。
TokenStartIndex:获取最后一个已处理的JSON令牌开始的索引(在给定UTF-8编码的输入文本中),跳过任何空格。
TokenType:获取UTF-8编码的JSON文本中最后处理的JSON标志的类型。
ValueSequence:仅当标志包含在多个段中时,获取作为输入负载的ReadOnlySequence片的最后处理标志的原始值。
ValueSpan:如果标志适合单个段,或者如果读取器是用ReadOnlySpan中包含的JSON有效载荷构造的,则获取作为输入有效载荷的ReadOnlySpan片的最后处理令牌的原始值。

 主要方法

Get基础数据类型() :获取当前token的数据格式。
GetComment() :获取注释
GetGuid():
GetDateTimeOffset
Read():读取一个Token
Skip:跳过

实战案例

案例一、Read()+TokenType+TokenStartIndex

在项目目录下新建文件“sample.json”,输入以下信息然后保存

{
"postTitle":"Programming",
"language":"C#",
"author":{
    "firstName":"Nick " ,
    "lastName ":"Carter"
            },
"publishedAt":"2019-10-22T20:50:21.000Z",
"wordCount":13435,
"isoriginal": true,
"tags":[ "C#","JSON API",".NET Core"]
}

代码如下

var sampleJson= File.ReadAllBytes("sample.json").AsSpan();
Utf8JsonReader reader=new Utf8JsonReader(sampleJson);
while (reader.Read())//reader就会移动到JSON数据里面的下一个Token那里
{
    string item = SwitchToken(reader);
    if (reader.TokenType==JsonTokenType.PropertyName)
    {
        string startIndex = reader.TokenStartIndex.ToString();//token 开始字符为止
        Console.Write(startIndex   + item + ":"  );
    }
    else { Console.WriteLine(item); }
    Console.WriteLine(reader.CurrentDepth);
    Console.WriteLine(reader.CurrentState);
}

string SwitchToken(Utf8JsonReader reader) =>
    reader.TokenType switch
    {
        JsonTokenType .StartObject=> "{",
        JsonTokenType.EndObject => "}",
        JsonTokenType.StartArray => "[",
        JsonTokenType.EndArray => "]",
        JsonTokenType.False => $"{reader.GetBoolean()}," ,
        JsonTokenType.PropertyName =>$@"""{ reader.GetString()!}""",

        JsonTokenType.True => $"{reader.GetBoolean()}," ,
        JsonTokenType.Number => $"{reader.GetInt32()}," ,

        JsonTokenType.String => @$"""{reader.GetString()}"","  ,
        JsonTokenType.Null=> "Null",
        _ => "None",
    };

 

【解说】

Main方法里面,我们使用File.ReadAllBytes从sample.json文件读取数格式为byte[],然后通过AsSpan这个扩展方法将其转化为Span<byte>数据类型,然后把它传递到 Utf8JsonReader 的构造函数来创建一个JSON的reader。
接下来使用while循环对JSON数据的每个Token进行读取,每次执行Read()方法时,reader就会移动到JSON数据里面的下一个Token那里

 

案例二、转换器

自定义基本模式转换器 ,采用反射方式的序列化

  1. 将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。
  2. 将 [JsonConverter] 特性应用于需要自定义转换器的属性或者将 [JsonConverter] 属性应用于表示自定义值类型的类或结构。
JsonSerializerOptions op = new JsonSerializerOptions
{
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
    Converters = { new MYEnumToUpperStingConverter() },//将转换器类的实例添加到 JsonSerializerOptions.Converters 集合中。

    WriteIndented = true,
};

WeatherForecastWithEnum wf=new WeatherForecastWithEnum();   
string wfw= JsonSerializer.Serialize(wf, op);
WeatherForecastWithEnum wff=JsonSerializer.Deserialize<WeatherForecastWithEnum>(wfw,op);
Console.WriteLine( wfw);
public class MYEnumToUpperStingConverter : JsonConverter<Summary>
{

    public override Summary Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return (Summary)Enum.Parse(typeToConvert, reader.GetString());
    }

    public override void Write(Utf8JsonWriter writer, Summary value, JsonSerializerOptions options)
    {
        writer.WriteStringValue( Enum.GetName(value));
    }
}


public class WeatherForecastWithEnum
{
   
    public DateTimeOffset Date { get; set; } = DateTime.Now;
    public int TemperatureCelsius { get; set; } = new Random().Next(1000);

    [JsonConverter(typeof(MYEnumToUpperStingConverter))]//将 [JsonConverter] 特性应用于需要自定义转换器的属性。
    public Summary Summaryp { get; set; } = Summary.Cold;

    [JsonConverter(typeof(MYEnumToUpperStingConverter))]
    public Summary Summaryp2 { get; set; } = Summary.Cold;
}

public enum Summary
{
    Cold, Cool, Warm, Hot
}

 Utf8JsonWriter

 综合应用  采用反射方式的序列化

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace WriteRawJson
{
    public class Program
    {/*w  w    w  .  de    mo    2 s   .c  o    m*/
        public static void Main()
        {
            JsonWriterOptions writerOptions = new() { Indented = true, Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping };
            using MemoryStream stream = new();
            using Utf8JsonWriter writer = new(stream, writerOptions);
            writer.WriteStartObject();

            // writer.WritePropertyName("defaultJsonFormatting");
            // writer.WriteStartArray();
            //or
            writer.WriteStartArray("defaultJsonFormatting");

            foreach (double number in new double[] { 50.4, 51 })
            {
                writer.WriteStartObject();

                writer.WritePropertyName("value");
                writer.WriteNumberValue(number);

                writer.WriteNull("Wait");// "Wait": null
                //or
                writer.WritePropertyName("Wait2");// "Wait2": null
                writer.WriteNullValue();

                writer.WriteString("WriteString", "dsfsdf");
                //or
                writer.WritePropertyName("WriteString1");// "Wait2": null
                writer.WriteStringValue("value");

                writer.WriteCommentValue("Comment");// 注释/*Comment*/
                writer.WriteEndObject();
            }
            writer.WriteEndArray();
            writer.WriteStartArray("customJsonFormatting");
            foreach (double result in new double[] { 50.4, 51 })
            {
                writer.WriteStartObject();
                writer.WritePropertyName("value");
                writer.WriteRawValue( //  验证输入是否为符合 RFC 8259 的 JSON 
                    FormatNumberValue(result), skipInputValidation: true);
                writer.WriteEndObject();
            }
            writer.WriteEndArray();
            writer.WriteEndObject();
            writer.Flush();
            string json = Encoding.UTF8.GetString(stream.ToArray());

            Console.WriteLine(json);
            JsonSerializerOptions options = new JsonSerializerOptions { ReadCommentHandling = JsonCommentHandling.Skip };// 跳过注释
            Rootobject rootobject = JsonSerializer.Deserialize<Rootobject>(json, options);

        }
        static string FormatNumberValue(double numberValue)
        {
            return numberValue == Convert.ToInt32(numberValue) ?
                numberValue.ToString() + ".0" : numberValue.ToString();
        }
    }

    //拷贝Jsonstring 然后选择菜单 【编辑】>选择性粘贴>将Json粘贴为类
    public class Rootobject
    {
        public Defaultjsonformatting[] defaultJsonFormatting { get; set; }
        public Customjsonformatting[] customJsonFormatting { get; set; }
    }

    public class Defaultjsonformatting
    {
        public float value { get; set; }
        public object Wait { get; set; }
        public object Wait2 { get; set; }
        public string WriteString { get; set; }
        public string WriteString1 { get; set; }
    }

    public class Customjsonformatting
    {
        public float value { get; set; }
    }


}
/*输出:
    {
  "defaultJsonFormatting": [
    {
      "value": 50.4,
      "Wait": null,
      "Wait2": null,
      "WriteString": "dsfsdf",
      "WriteString1": "value"
      /*Comment*//*
    },
    {
    "value": 51,
      "Wait": null,
      "Wait2": null,
      "WriteString": "dsfsdf",
      "WriteString1": "value"
     /*Comment*//*
    }
  ],
  "customJsonFormatting": [
    {
      "value": 50.4
    },
    {
    "value": 51.0
    }
  ]
}
**//*/

 

posted @ 2022-03-21 18:26  小林野夫  阅读(2286)  评论(0编辑  收藏  举报
原文链接:https://www.cnblogs.com/cdaniu/