【C# 序列化】 Utf8JsonReader和Utf8JsonWriter


简介

【C# 序列化】 ReadOnlySequence

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

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

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

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

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

ReadOnlySpan高性能内存空间读取数据结构。支持数组、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数据类型,然后把它传递到 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(wfw,op);
Console.WriteLine( wfw);
public class MYEnumToUpperStingConverter : JsonConverter
{

    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
}
C