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,
};
}
}
}