簡介
【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那里
案例二、轉換器
自定義基本模式轉換器 ,采用反射方式的序列化
- 將轉換器類的實例添加到 JsonSerializerOptions.Converters 集合中。
- 將 [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 } ] } **//*/