using MessagePack; using Newtonsoft.Json; using System.Diagnostics.CodeAnalysis; using System.Text; using System.Text.Encodings.Web; using System.Threading; using static Newtonsoft.Json.JsonConvert; using static System.Serializable; using SJsonSerializer = System.Text.Json.JsonSerializer; using SJsonSerializerOptions = System.Text.Json.JsonSerializerOptions; namespace System { /// /// 序列化、反序列化,模型类可继承此类 /// [Serializable] public abstract partial class Serializable { /// /// 序列化程式实现种类 /// public enum ImplType { /// /// Newtonsoft.Json /// https://github.com/JamesNK/Newtonsoft.Json /// NewtonsoftJson, /// /// MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it's faster and smaller. Small integers are encoded into a single byte, and typical short strings require only one extra byte in addition to the strings themselves. /// https://msgpack.org/ /// https://github.com/neuecc/MessagePack-CSharp /// MessagePack, /// /// System.Text.Json /// 仅用于 .Net Core 3+ / Web,因 Emoji 字符被转义 /// https://github.com/dotnet/corefx/tree/v3.1.5/src/System.Text.Json /// https://github.com/dotnet/runtime/tree/v5.0.0-preview.6.20305.6/src/libraries/System.Text.Json /// SystemTextJson, } /// /// JSON 序列化程式实现种类 /// public enum JsonImplType { /// NewtonsoftJson = ImplType.NewtonsoftJson, /// SystemTextJson = ImplType.SystemTextJson, } #region DefaultJsonImplType /// /// JSON 序列化程式 实现,可设置使用 Newtonsoft.Json 或 System.Text.Json /// public static JsonImplType DefaultJsonImplType { get; set; } = GetDefaultJsonImplType(); static JsonImplType GetDefaultJsonImplType() { if (DI.Platform == Platform.Android || (DI.Platform == Platform.Apple && DI.DeviceIdiom != DeviceIdiom.Desktop)) { return JsonImplType.NewtonsoftJson; } return JsonImplType.SystemTextJson; } #endregion #region Serialize(序列化) /// /// (Serialize)JSON 序列化 /// /// /// /// /// /// /// public static string SJSON(JsonImplType implType, object? value, Type? inputType = null, bool writeIndented = false, bool ignoreNullValues = false) { switch (implType) { case JsonImplType.SystemTextJson: var options = new SJsonSerializerOptions { Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping, WriteIndented = writeIndented, IgnoreNullValues = ignoreNullValues }; return SJsonSerializer.Serialize(value, inputType ?? value?.GetType() ?? typeof(object), options); default: var formatting = writeIndented ? Formatting.Indented : Formatting.None; var settings = ignoreNullValues ? new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore } : null; return SerializeObject(value, inputType, formatting, settings); } } /// /// (Serialize)JSON 序列化 /// /// /// /// /// public static string SJSON(object? value, Type? inputType = null, bool writeIndented = false, bool ignoreNullValues = false) => SJSON(DefaultJsonImplType, value, inputType, writeIndented, ignoreNullValues); /// /// (Serialize)MessagePack 序列化 /// /// /// /// public static byte[] SMP(T value, CancellationToken cancellationToken = default) => MessagePackSerializer.Serialize(value, cancellationToken: cancellationToken); /// /// (Serialize)MessagePack 序列化 + Base64Url Encode /// /// /// /// /// public static string? SMPB64U(T value, CancellationToken cancellationToken = default) { if (value == null) return null; var byteArray = SMP(value, cancellationToken); return byteArray.Base64UrlEncode_Nullable(); } #endregion #region Deserialize(反序列化) /// /// (Deserialize)JSON 反序列化 /// /// /// /// /// [return: MaybeNull] public static T DJSON(JsonImplType implType, string value) { return implType switch { JsonImplType.SystemTextJson => SJsonSerializer.Deserialize(value), _ => DeserializeObject(value), }; } /// /// (Deserialize)JSON 反序列化 /// /// /// /// [return: MaybeNull] public static T DJSON(string value) => DJSON(DefaultJsonImplType, value); /// /// (Deserialize)MessagePack 反序列化 /// /// /// /// [return: MaybeNull] public static T DMP(byte[] buffer, CancellationToken cancellationToken = default) => MessagePackSerializer.Deserialize(buffer, cancellationToken: cancellationToken); /// /// (Deserialize)MessagePack 反序列化 + Base64Url Decode /// /// /// /// /// [return: MaybeNull] public static T DMPB64U(string? value, CancellationToken cancellationToken = default) { if (!string.IsNullOrWhiteSpace(value)) { try { var buffer = value.Base64UrlDecodeToByteArray(); return DMP(buffer, cancellationToken); } catch { } } return default; } #endregion /// /// 使用 MessagePack 序列化将对象克隆一份新的对象 /// /// /// /// public static T Clone(T obj) { var bytes = MessagePackSerializer.Serialize(obj); return MessagePackSerializer.Deserialize(bytes); } } public static class SerializableExtensions { /// public static T Clone(this T obj) where T : Serializable => Serializable.Clone(obj); /// /// 将 [序列化程式实现种类] 转换为 [JSON 序列化程式实现种类] /// /// /// /// public static bool TryConvert(this ImplType @enum, out JsonImplType value) { switch (@enum) { case ImplType.NewtonsoftJson: value = JsonImplType.NewtonsoftJson; return true; case ImplType.SystemTextJson: value = JsonImplType.SystemTextJson; return true; default: value = default; return false; } } /// /// 将 [JSON 序列化程式实现种类] 转换为 [序列化程式实现种类] /// /// /// public static ImplType Convert(this JsonImplType value) { return value switch { JsonImplType.SystemTextJson => ImplType.SystemTextJson, _ => ImplType.NewtonsoftJson, }; } } }