diff --git a/README.md b/README.md index e023be690c6b93123c603601d838800d58dfecf0..d0216928977225873d0855ddea1e2a6f41fe1a1e 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,7 @@ **注意:** -- **从 3.0 后分离了各个功能包,极力避免`DotNetCommon.Core`对其他包的依赖;** - -- **从 4.0 后使用`SharpCompress`替代`SharpZipLib` 封装解压缩功能;** +- **从 4.0 后移除了对`Newtonsoft.Json`的依赖,这样`DotNetCommon.Core`将不依赖任何三方包;** **整体关系如下图:** @@ -30,9 +28,7 @@ > > 1. DotNetCommon包 具有所有功能,引用了其他的各个功能包; > -> 2. DotNeCommon.Core 是核心包,在 `https://github.com/NimaAra/Easy.Common`基础上扩充而成; -> -> 虽然,极力在避免其他的依赖,但还是无法避免对`Newtonsoft.Json`的引用,因为`System.Text.Json`不支持`jsonpath`。 +> 2. DotNeCommon.Core 是核心包,在 `https://github.com/NimaAra/Easy.Common`基础上扩充而成,从DotNetCommon.Core4.0.0开始移除了对Newtonsoft.Json的依赖,之后将不再依赖任何三方包; > > 3. DotNetCommon.PinYin 是汉字转拼音包,从`https://github.com/toolgood/ToolGood.Words.Pinyin`搬运; > diff --git a/docs/README.md b/docs/README.md index 72892565cdbb7379c15d5c0a511569bd1fc5cfed..859f897ec3c6eedf1c5f629bae162a12164ac931 100644 --- a/docs/README.md +++ b/docs/README.md @@ -16,9 +16,7 @@ **注意:** -- **从 3.0 后分离了各个功能包,极力避免`DotNetCommon.Core`对其他包的依赖;** - -- **从 4.0 后使用`SharpCompress`替代`SharpZipLib`封装解压缩功能;** +- **从 4.0 后移除了对`Newtonsoft.Json`的依赖,这样`DotNetCommon.Core`将不依赖任何三方包;** **整体关系如下图:** @@ -30,9 +28,7 @@ > > 1. DotNetCommon包 具有所有功能,引用了其他的各个功能包; > -> 2. DotNeCommon.Core 是核心包,在 `https://github.com/NimaAra/Easy.Common`基础上扩充而成; -> -> 虽然,极力在避免其他的依赖,但还是无法避免对`Newtonsoft.Json`的引用,因为`System.Text.Json`不支持`jsonpath`。 +> 2. DotNeCommon.Core 是核心包,在 `https://github.com/NimaAra/Easy.Common`基础上扩充而成,从DotNetCommon.Core4.0.0开始移除了对Newtonsoft.Json的依赖,之后将不再依赖任何三方包; > > 3. DotNetCommon.PinYin 是汉字转拼音包,从`https://github.com/toolgood/ToolGood.Words.Pinyin`搬运; > diff --git a/docs/imgs/image-20221101092958287.png b/docs/imgs/image-20221101092958287.png index b157cdf4fa746a4c28304be5b43ae98c4afbf695..e96c59fd6ffd94335f139525364b9276db443a94 100644 Binary files a/docs/imgs/image-20221101092958287.png and b/docs/imgs/image-20221101092958287.png differ diff --git a/src/DotNetCommon.Compress/CompressHelper.cs b/src/DotNetCommon.Compress/CompressHelper.cs index 05de41ee1d39978006f508ba690b5b65383706e5..ac166cfcbc70c082fe3d839e60136982730cf11f 100644 --- a/src/DotNetCommon.Compress/CompressHelper.cs +++ b/src/DotNetCommon.Compress/CompressHelper.cs @@ -224,7 +224,7 @@ namespace DotNetCommon.Compress } else if (new[] { ".zip", ".7z" }.Any(i => src.EndsWith(i, StringComparison.OrdinalIgnoreCase))) { - var archive = ArchiveFactory.Open(src, GetReaderOptions()); + using var archive = ArchiveFactory.Open(src, GetReaderOptions()); foreach (var entry in archive.Entries) { if (!entry.IsDirectory) diff --git a/src/DotNetCommon.Core/Data/Page.cs b/src/DotNetCommon.Core/Data/Page.cs index b73c7a66a25144a590bcc95a386012e51164383d..4b2c2a68e76dc55425f4685d7077202981791a27 100644 --- a/src/DotNetCommon.Core/Data/Page.cs +++ b/src/DotNetCommon.Core/Data/Page.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; @@ -9,7 +8,6 @@ namespace DotNetCommon.Data /// /// 分页数据 /// - [JsonObject(MemberSerialization.OptOut)] [DataContract] public class Page { diff --git a/src/DotNetCommon.Core/Data/PageQuery.cs b/src/DotNetCommon.Core/Data/PageQuery.cs index 7ece93ffc926d8701f2b74256fcfbb41de8aaed9..f884d01f24a25ddb5597b8c3324159d302950e50 100644 --- a/src/DotNetCommon.Core/Data/PageQuery.cs +++ b/src/DotNetCommon.Core/Data/PageQuery.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; @@ -9,7 +8,6 @@ namespace DotNetCommon.Data /// /// 分页查询请求 /// - [JsonObject(MemberSerialization.OptOut)] [DataContract] public class PageQuery { diff --git a/src/DotNetCommon.Core/Data/Result.cs b/src/DotNetCommon.Core/Data/Result.cs index dd3162a169832655f3b9ac16e2407e282107ab6f..be9979339154d40fa91184a891b59bea1ef54fa6 100644 --- a/src/DotNetCommon.Core/Data/Result.cs +++ b/src/DotNetCommon.Core/Data/Result.cs @@ -1,8 +1,8 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using System.Text.Json; using System.Threading.Tasks; using DotNetCommon.Extensions; @@ -11,7 +11,6 @@ namespace DotNetCommon.Data /// /// 通用结果模型 /// - [JsonObject(MemberSerialization.OptOut)] [DataContract] public class Result { @@ -123,7 +122,7 @@ namespace DotNetCommon.Data if (data == null) this.Data = default(T); else { - this.Data = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(data)); + this.Data = JsonSerializer.Deserialize(JsonSerializer.Serialize(data)); } } return this; @@ -308,8 +307,8 @@ namespace DotNetCommon.Data Success = true, Data = t }; - var json = Newtonsoft.Json.JsonConvert.SerializeObject(value); - t = Newtonsoft.Json.JsonConvert.DeserializeObject(json); + var json = System.Text.Json.JsonSerializer.Serialize(value); + t = System.Text.Json.JsonSerializer.Deserialize(json); return new Result() { Success = true, diff --git a/src/DotNetCommon.Core/Data/ResultPage.cs b/src/DotNetCommon.Core/Data/ResultPage.cs index c8638937478511e6dbd9e52b7a6f7abd2a2fca6d..a2f794ce2c81d272da55d904147560d2dc54156a 100644 --- a/src/DotNetCommon.Core/Data/ResultPage.cs +++ b/src/DotNetCommon.Core/Data/ResultPage.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; @@ -9,7 +8,6 @@ namespace DotNetCommon.Data /// /// 返回分页结果数据 /// - [JsonObject(MemberSerialization.OptOut)] [DataContract] public class ResultPage : Result> { diff --git a/src/DotNetCommon.Core/Data/TreeNode.cs b/src/DotNetCommon.Core/Data/TreeNode.cs index 46b588008b509fb2e0f75fcf4a641d41eacdfa95..f6070f17212c3cbfa4108f358008acdf87b10db1 100644 --- a/src/DotNetCommon.Core/Data/TreeNode.cs +++ b/src/DotNetCommon.Core/Data/TreeNode.cs @@ -1,5 +1,4 @@ -using Newtonsoft.Json; -using System; +using System; using System.Collections.Generic; using System.Runtime.Serialization; using System.Text; @@ -10,7 +9,6 @@ namespace DotNetCommon.Data /// 树节点模型 /// /// 模型数据 - [JsonObject(MemberSerialization.OptOut)] [DataContract] public sealed class TreeNode { diff --git a/src/DotNetCommon.Core/DeepCloneHelper.cs b/src/DotNetCommon.Core/DeepCloneHelper.cs index 773eb804a76f72e622721611d9511635fcec41ee..fb869b200947c6f59e7237437345b782d4cc5015 100644 --- a/src/DotNetCommon.Core/DeepCloneHelper.cs +++ b/src/DotNetCommon.Core/DeepCloneHelper.cs @@ -1,6 +1,5 @@ using DotNetCommon.Data; using DotNetCommon.Extensions; -using Newtonsoft.Json.Linq; using System; using System.Collections; using System.Collections.Concurrent; @@ -10,6 +9,9 @@ using System.Linq.Expressions; using System.Numerics; using System.Reflection; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; namespace DotNetCommon { @@ -184,19 +186,51 @@ namespace DotNetCommon } else if (reflect.Name == "Newtonsoft.Json.Linq.JObject") { - wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : (obj as JObject).DeepClone(); + var tmp = type.Assembly.GetType("Newtonsoft.Json.Linq.JObject"); + var tmp2 = tmp.GetMethod("DeepClone"); + var tmp3 = Expression.Parameter(typeof(object), "obj"); + var act = Expression.Lambda>(Expression.Call(Expression.TypeAs(tmp3, tmp), tmp2), tmp3).Compile(); + wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : act(obj); return wrapper; } else if (reflect.Name == "Newtonsoft.Json.Linq.JArray") { - wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : (obj as JArray).DeepClone(); + var tmp = type.Assembly.GetType("Newtonsoft.Json.Linq.JArray"); + var tmp2 = tmp.GetMethod("DeepClone"); + var tmp3 = Expression.Parameter(typeof(object), "obj"); + var act = Expression.Lambda>(Expression.Call(Expression.TypeAs(tmp3, tmp), tmp2), tmp3).Compile(); + wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : act(obj); return wrapper; } else if (reflect.Name == "Newtonsoft.Json.Linq.JToken") { - wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : (obj as JToken).DeepClone(); + var tmp = type.Assembly.GetType("Newtonsoft.Json.Linq.JToken"); + var tmp2 = tmp.GetMethod("DeepClone"); + var tmp3 = Expression.Parameter(typeof(object), "obj"); + var act = Expression.Lambda>(Expression.Call(Expression.TypeAs(tmp3, tmp), tmp2), tmp3).Compile(); + wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : act(obj); return wrapper; } + #region TODO JsonObject/JsonArray/JsonDocument 原生没有提供clone方法 + else if (reflect.Name == "System.Text.Json.Nodes.JsonObject") + { + Func act = (obj) => JsonObject.Parse((obj as JsonObject).ToJsonString()); + wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : act(obj); + return wrapper; + } + else if (reflect.Name == "System.Text.Json.Nodes.JsonArray") + { + Func act = (obj) => JsonArray.Parse((obj as JsonArray).ToJsonString()); + wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : act(obj); + return wrapper; + } + else if (reflect.Name == "System.Text.Json.JsonDocument") + { + Func act = (obj) => JsonDocument.Parse(JsonSerializer.Serialize(obj as JsonDocument)); + wrapper.Method = (obj, dic) => dic.ContainsKey(obj) ? dic.get_Item(obj) : act(obj); + return wrapper; + } + #endregion else if (reflect.Name == "System.Collections.Generic.List") { GetCloneMethod_List(type, reflect, wrapper, tmpCache); diff --git a/src/DotNetCommon.Core/DotNetCommon.Core.csproj b/src/DotNetCommon.Core/DotNetCommon.Core.csproj index d46901c34b5f7c3a3ea519350da0070bca1979f8..7ab716c46dd12c6466ab2e5a3ef971d14206ac02 100644 --- a/src/DotNetCommon.Core/DotNetCommon.Core.csproj +++ b/src/DotNetCommon.Core/DotNetCommon.Core.csproj @@ -1,7 +1,7 @@ - 3.2.0 + 4.0.0 True .net常用功能及数据模型,包含: @@ -44,7 +44,4 @@ \ - - - diff --git a/src/DotNetCommon.Core/Extensions/ObjectExtensions.cs b/src/DotNetCommon.Core/Extensions/ObjectExtensions.cs index fdddb76f1846b8a8faa47964f9a180a80fb70b39..6bceac613b642e146be4cd1b047d44372815e9aa 100644 --- a/src/DotNetCommon.Core/Extensions/ObjectExtensions.cs +++ b/src/DotNetCommon.Core/Extensions/ObjectExtensions.cs @@ -1,7 +1,4 @@ using DotNetCommon.Serialize; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.ComponentModel; @@ -13,12 +10,13 @@ using DotNetCommon.Logger; using System.Reflection; using System.Threading; using System.Collections.Concurrent; -using DateTimeConverter = DotNetCommon.Serialize.DateTimeConverter; using System.Collections.ObjectModel; using System.Threading.Tasks; using System.IO; using System.Collections; using static System.Net.Mime.MediaTypeNames; +using System.Text.Json; +using System.Linq.Expressions; namespace DotNetCommon.Extensions { @@ -413,13 +411,13 @@ namespace DotNetCommon.Extensions } #endregion #region 其他 使用 JsonConvert 实现 - return JsonConvert.DeserializeObject(JsonConvert.SerializeObject(value), type); + return JsonSerializer.Deserialize(JsonSerializer.Serialize(value), type); #endregion } else { //兼容从json字符串反序列化 - if (value is string && type.IsClass) return JsonConvert.DeserializeObject(value.ToString(), type); + if (value is string && type.IsClass) return JsonSerializer.Deserialize(value.ToString(), type); //引用类型 return value; } @@ -1127,16 +1125,100 @@ namespace DotNetCommon.Extensions }; #region ToJson & ToJsonFast + private static Func _getNewtonsoftJsonSerialize = null; + private static Func getNewtonsoftJsonSerialize(Assembly assembly) + { + if (_getNewtonsoftJsonSerialize == null) + { + var tmp = assembly.GetType("Newtonsoft.Json.JsonConvert"); + var method = tmp.GetMethods().FirstOrDefault(i => i.Name == "SerializeObject" && i.GetParameters().Length == 1); + var para = Expression.Parameter(typeof(object), "obj"); + _getNewtonsoftJsonSerialize = Expression.Lambda>(Expression.Call(null, method, new Expression[] { para }), para).Compile(); + } + return _getNewtonsoftJsonSerialize; + } + + private static Func _getNewtonsoftJsonSerialize2 = null; + /// + /// 其实 JObject/JArray 转 json, 也就 isIntend 生效 + /// + /// + /// + private static Func getNewtonsoftJsonSerialize2(Assembly assembly) + { + if (_getNewtonsoftJsonSerialize2 == null) + { + var tmp = assembly.GetType("Newtonsoft.Json.JsonConvert"); + var tmp2 = assembly.GetType("Newtonsoft.Json.JsonSerializerSettings"); + var method = tmp.GetMethods().FirstOrDefault(i => i.Name == "SerializeObject" && i.GetParameters().Length == 2 && i.GetParameters().LastOrDefault().ParameterType == tmp2); + var para = Expression.Parameter(typeof(object), "obj"); + var para_DateFormatString = Expression.Parameter(typeof(string), "DateFormatString"); + var para_NullValueHandling = Expression.Parameter(typeof(bool), "NullValueHandling"); + var para_StringEnumConverter = Expression.Parameter(typeof(bool), "StringEnumConverter"); + var para_ContractResolver = Expression.Parameter(typeof(bool), "ContractResolver"); + var para_Formatting = Expression.Parameter(typeof(bool), "Formatting"); + + var local_settings = Expression.Variable(tmp2, "settings"); + var tmp3 = assembly.GetType("Newtonsoft.Json.NullValueHandling"); + var tmp4 = assembly.GetType("Newtonsoft.Json.Converters.StringEnumConverter"); + var tmp5 = assembly.GetType("Newtonsoft.Json.JsonConverter"); + var tmp6 = assembly.GetType("Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver"); + var tmp7 = assembly.GetType("Newtonsoft.Json.Formatting"); + + var assign_local = Expression.Assign(local_settings, Expression.New(tmp2.GetConstructor(new Type[0]))); + var assign_DateFormatString = Expression.IfThen(Expression.NotEqual(para_DateFormatString, Expression.Constant(null)), Expression.Assign(Expression.MakeMemberAccess(local_settings, tmp2.GetProperty("DateFormatString")), para_DateFormatString)); + var assign_NullValueHandling = Expression.IfThen(Expression.Equal(para_NullValueHandling, Expression.Constant(true)), Expression.Assign(Expression.MakeMemberAccess(local_settings, tmp2.GetProperty("NullValueHandling")), Expression.Convert(Expression.Constant(1), tmp3))); + + //var addMethod = typeof(List<>).MakeGenericType(tmp5).GetMethod("Add"); + var addMethod = typeof(ICollection<>).MakeGenericType(tmp5).GetMethod("Add"); + var assign_StringEnumConverter = Expression.IfThen(Expression.Equal(para_StringEnumConverter, Expression.Constant(true)), Expression.Call(Expression.Property(local_settings, "Converters"), addMethod, Expression.New(tmp4))); + var assign_ContractResolver = Expression.IfThen(Expression.Equal(para_ContractResolver, Expression.Constant(true)), Expression.Assign(Expression.Property(local_settings, "ContractResolver"), Expression.New(tmp6.GetConstructor(new Type[0])))); + var assign_Formatting = Expression.IfThen(Expression.Equal(para_Formatting, Expression.Constant(true)), Expression.Assign(Expression.Property(local_settings, "Formatting"), Expression.Convert(Expression.Constant(1), tmp7))); + + var finalCall = Expression.Call(null, method, para, local_settings); + + _getNewtonsoftJsonSerialize2 = Expression.Lambda>(Expression.Block(new ParameterExpression[] { local_settings }, + assign_local, + assign_DateFormatString, + assign_NullValueHandling, + assign_StringEnumConverter, + assign_ContractResolver, + assign_Formatting, + finalCall) + , para, para_DateFormatString, para_NullValueHandling, para_StringEnumConverter, para_ContractResolver, para_Formatting + ).Compile(); + } + return _getNewtonsoftJsonSerialize2; + } + /// /// 序列化为json字符串 /// /// - /// 序列化设置对象 + /// 序列化设置对象 /// - public static string ToJson(this object obj, JsonSerializerSettings settings = null) + public static string ToJson(this object obj, JsonSerializerOptions options = null) { if (obj == null) return null; - return Newtonsoft.Json.JsonConvert.SerializeObject(obj, settings); + var fullName = obj.GetType().GetClassFullName(); + if (fullName == "Newtonsoft.Json.Linq.JObject" || fullName == "Newtonsoft.Json.Linq.JArray") + { + var act = getNewtonsoftJsonSerialize(obj.GetType().Assembly); + return act(obj); + } + if (options == null) + { + options = new JsonSerializerOptions + { + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + } + if (Environment.Version.Major == 6) + { + options.Converters.Add(new JsonConverterDateOnly()); + options.Converters.Add(new JsonConverterTimeOnly()); + } + return System.Text.Json.JsonSerializer.Serialize(obj, options); } /// @@ -1144,42 +1226,43 @@ namespace DotNetCommon.Extensions /// /// /// 日期时间格式 - /// 是否将long型转为字符串 + /// 是否将数字转为字符串 /// 是否忽略null值的属性 /// 是否将枚举转换为字符串 /// 属性名称的首字母是否小写 /// 是否格式缩进 - /// 是否将所有数据类型转换为字符串 - /// 设定的所有数字的最大小数位数(默认为null,即: 不限制) - /// 仅针对decimal设定的最大小数位数(默认为null,即: 不限制) /// 其他的设置 /// - public static string ToJsonFast(this object obj, string dateFormatString = "yyyy-MM-dd HH:mm:ss", bool IgnoreNull = false, bool enum2String = true, bool lowerCamelCase = false, bool isIntend = false, bool isLongToString = false, bool isAllToString = false, int? allNumDigit = null, int? decimalDigit = null, Action otherSettings = null) + public static string ToJsonFast(this object obj, string dateFormatString = null, bool IgnoreNull = false, bool enum2String = false, bool lowerCamelCase = false, bool isIntend = false, bool number2String = false, Action otherSettings = null) { - var settings = new Newtonsoft.Json.JsonSerializerSettings() - { - DateFormatString = dateFormatString, - Converters = new List() - }; - if (IgnoreNull) + if (obj == null) return null; + var fullName = obj.GetType().GetClassFullName(); + if (fullName == "Newtonsoft.Json.Linq.JObject" || fullName == "Newtonsoft.Json.Linq.JArray") { - settings.NullValueHandling = NullValueHandling.Ignore; + var act = getNewtonsoftJsonSerialize2(obj.GetType().Assembly); + return act(obj, dateFormatString, IgnoreNull, enum2String, lowerCamelCase, isIntend); } - if (enum2String) + var options = new JsonSerializerOptions() { - settings.Converters.Add(new StringEnumConverter()); - } - if (lowerCamelCase) + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }; + if (Environment.Version.Major == 6) { - settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); + options.Converters.Add(new JsonConverterDateOnly()); + options.Converters.Add(new JsonConverterTimeOnly()); } - if (isIntend) + if (dateFormatString.IsNotNullOrEmptyOrWhiteSpace()) { - settings.Formatting = Formatting.Indented; + options.Converters.Add(new JsonConverterDatetime(dateFormatString)); + options.Converters.Add(new JsonConverterDateTimeOffset(dateFormatString)); } - settings.Converters.Add(new PrimitiveConvertor(isLongToString, isAllToString, allNumDigit, decimalDigit)); - otherSettings?.Invoke(settings); - return JsonConvert.SerializeObject(obj, settings); + if (IgnoreNull) options.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull; + if (enum2String) options.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter()); + if (lowerCamelCase) options.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase; + if (isIntend) options.WriteIndented = true; + if (number2String) options.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.WriteAsString; + otherSettings?.Invoke(options); + return JsonSerializer.Serialize(obj, options); } #endregion diff --git a/src/DotNetCommon.Core/Extensions/StringExtensions.cs b/src/DotNetCommon.Core/Extensions/StringExtensions.cs index 93ba9daf3f0483a3acf6fb9a51cf8d961128f7ac..73bbbac51ea26575132782fcedc7aa0df880854d 100644 --- a/src/DotNetCommon.Core/Extensions/StringExtensions.cs +++ b/src/DotNetCommon.Core/Extensions/StringExtensions.cs @@ -1,5 +1,4 @@ using DotNetCommon; -using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; @@ -7,7 +6,11 @@ using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; +using System.Linq.Expressions; +using System.Reflection; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Text.RegularExpressions; using System.Threading; using System.Xml; @@ -416,32 +419,69 @@ namespace DotNetCommon.Extensions /// public static int GetSize(this string input) => input.Length * sizeof(char); + private static Func jobjectFunc = null; + private static Func getJObjectParseFunc(Assembly assembly) + { + if (jobjectFunc == null) + { + var tmp = assembly.GetType("Newtonsoft.Json.Linq.JObject"); + var parseMehtod = tmp.GetMethods().FirstOrDefault(i => i.Name == "Parse" && i.GetParameters().Length == 2); + var tmp2 = assembly.GetType("Newtonsoft.Json.Linq.JsonLoadSettings"); + var para = Expression.Parameter(typeof(string), "input"); + var ctor = tmp2.GetConstructors().FirstOrDefault(); + //数字 枚举转换 + var enumType = assembly.GetType("Newtonsoft.Json.Linq.CommentHandling"); + + var memberInit = Expression.MemberInit(Expression.New(ctor), Expression.Bind(tmp2.GetProperty("CommentHandling"), Expression.Convert(Expression.Constant(0), enumType))); + jobjectFunc = Expression.Lambda>(Expression.Call(null, parseMehtod, para, memberInit), para).Compile(); + } + return jobjectFunc; + } + + private static Func jarrFunc = null; + private static Func getJArrayParseFunc(Assembly assembly) + { + if (jarrFunc == null) + { + var tmp = assembly.GetType("Newtonsoft.Json.Linq.JArray"); + var parseMehtod = tmp.GetMethods().FirstOrDefault(i => i.Name == "Parse" && i.GetParameters().Length == 2); + var tmp2 = assembly.GetType("Newtonsoft.Json.Linq.JsonLoadSettings"); + var para = Expression.Parameter(typeof(string), "input"); + var ctor = tmp2.GetConstructors().FirstOrDefault(); + //数字 枚举转换 + var enumType = assembly.GetType("Newtonsoft.Json.Linq.CommentHandling"); + var memberInit = Expression.MemberInit(Expression.New(ctor), Expression.Bind(tmp2.GetProperty("CommentHandling"), Expression.Convert(Expression.Constant(0), enumType))); + jarrFunc = Expression.Lambda>(Expression.Call(null, parseMehtod, para, memberInit), para).Compile(); + } + return jarrFunc; + } + /// /// 使用json的反序列化将字符串转为对象 /// /// /// json字符串 - /// 是否忽略json中的注释 /// - public static T ToObject(this string input, bool ignoreComment = false) + public static T ToObject(this string input) { - if (ignoreComment && typeof(T) == typeof(JObject)) + if (typeof(T).GetClassFullName() == "Newtonsoft.Json.Linq.JObject") { - var res = JObject.Parse(input, new JsonLoadSettings - { - CommentHandling = CommentHandling.Ignore - }).To(); - return res; + var act = getJObjectParseFunc(typeof(T).Assembly); + return (T)act(input); } - if (ignoreComment && typeof(T) == typeof(JArray)) + if (typeof(T).GetClassFullName() == "Newtonsoft.Json.Linq.JArray") { - var res = JArray.Parse(input, new JsonLoadSettings - { - CommentHandling = CommentHandling.Ignore - }).To(); - return res; + var act = getJArrayParseFunc(typeof(T).Assembly); + return (T)act(input); } - return Newtonsoft.Json.JsonConvert.DeserializeObject(input); + var options = new JsonSerializerOptions + { + AllowTrailingCommas = true, + ReadCommentHandling = System.Text.Json.JsonCommentHandling.Skip, + PropertyNameCaseInsensitive = true, + NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString, + }; + return JsonSerializer.Deserialize(input, options); } /// diff --git a/src/DotNetCommon.Core/JsonHelper.cs b/src/DotNetCommon.Core/JsonHelper.cs index bb512069dd513534895d91248b4739b24f7f3d51..bc5042a5c99af716743b94bd6ee5f064bae926f1 100644 --- a/src/DotNetCommon.Core/JsonHelper.cs +++ b/src/DotNetCommon.Core/JsonHelper.cs @@ -1,5 +1,5 @@ using DotNetCommon.Extensions; -using Newtonsoft.Json.Linq; +using System.Text.Json; namespace DotNetCommon { @@ -18,21 +18,17 @@ namespace DotNetCommon public static string Format(string srcJson, bool isIntend = true, bool removeComment = true) { if (srcJson.IsNullOrEmptyOrWhiteSpace()) return srcJson; - bool isArray = IsArray(srcJson); - if (isArray) + using var doc = JsonSerializer.Deserialize(srcJson, new JsonSerializerOptions { - return JArray.Parse(srcJson, new JsonLoadSettings - { - CommentHandling = removeComment ? CommentHandling.Ignore : CommentHandling.Load - }).ToString(isIntend ? Newtonsoft.Json.Formatting.Indented : Newtonsoft.Json.Formatting.None); - } - else + AllowTrailingCommas = true, + ReadCommentHandling = removeComment ? JsonCommentHandling.Skip : JsonCommentHandling.Allow, + }); + var res = JsonSerializer.Serialize(doc, new JsonSerializerOptions { - return JObject.Parse(srcJson, new JsonLoadSettings - { - CommentHandling = removeComment ? CommentHandling.Ignore : CommentHandling.Load - }).ToString(isIntend ? Newtonsoft.Json.Formatting.Indented : Newtonsoft.Json.Formatting.None); - } + WriteIndented = isIntend, + Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping, + }); + return res; } /// diff --git a/src/DotNetCommon.Core/MapperHelper.cs b/src/DotNetCommon.Core/MapperHelper.cs index c3abf7b4757bebfb1a08639ec4f879d0ab10cd74..8cf01bde1d0634940344cff8e352fc465078b29e 100644 --- a/src/DotNetCommon.Core/MapperHelper.cs +++ b/src/DotNetCommon.Core/MapperHelper.cs @@ -1,5 +1,4 @@ using DotNetCommon.Extensions; -using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Concurrent; @@ -10,6 +9,7 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Text; +using System.Text.Json; using static System.Net.Mime.MediaTypeNames; namespace DotNetCommon @@ -667,12 +667,12 @@ namespace DotNetCommon if (cacheKey.dest.IsNullable()) { //Console.WriteLine($"JsonConvert IsNullable: {cacheKey.from.GetClassFullName()} => {cacheKey.dest.GetClassFullName()}"); - wrapper.Method = (obj, dic, null2Default, args) => obj.IsNullOrDBNull() ? null : JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj), cacheKey.dest); + wrapper.Method = (obj, dic, null2Default, args) => obj.IsNullOrDBNull() ? null : JsonSerializer.Deserialize(JsonSerializer.Serialize(obj), cacheKey.dest); } else { //Console.WriteLine($"JsonConvert: {cacheKey.from.GetClassFullName()} => {cacheKey.dest.GetClassFullName()}"); - wrapper.Method = (obj, dic, null2Default, args) => obj.IsNullOrDBNull() ? nullFunc(null2Default) : JsonConvert.DeserializeObject(JsonConvert.SerializeObject(obj), cacheKey.dest); + wrapper.Method = (obj, dic, null2Default, args) => obj.IsNullOrDBNull() ? nullFunc(null2Default) : JsonSerializer.Deserialize(JsonSerializer.Serialize(obj), cacheKey.dest); } return wrapper; #endregion @@ -681,7 +681,7 @@ namespace DotNetCommon #region json字符串反序列化 if (cacheKey.from == typeof(string) && cacheKey.dest.IsClass) { - wrapper.Method = (obj, dic, null2Default, args) => obj.IsNullOrDBNull() ? null : JsonConvert.DeserializeObject(obj.ToString(), cacheKey.dest); + wrapper.Method = (obj, dic, null2Default, args) => obj.IsNullOrDBNull() ? null : JsonSerializer.Deserialize(obj.ToString(), cacheKey.dest); return wrapper; } #endregion diff --git a/src/DotNetCommon.Core/Serialize/DateTimeConverter.cs b/src/DotNetCommon.Core/Serialize/DateTimeConverter.cs index 7a4e74cf76df2d7b3c7a412c28611386a12a2252..4de83a4ef48f227d6d0de91dc3f3b1ffce7497fa 100644 --- a/src/DotNetCommon.Core/Serialize/DateTimeConverter.cs +++ b/src/DotNetCommon.Core/Serialize/DateTimeConverter.cs @@ -1,23 +1,97 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using System; -using System.Collections.Generic; -using System.Text; +using System; +using System.ComponentModel; namespace DotNetCommon.Serialize { /// - /// 日期格式转换器,定义在属性上比较方便( [JsonConverter(typeof(DateTimeConverter), "yyyy-MM-dd")]) + /// 专为 .net6 提供 /// - public sealed class DateTimeConverter : IsoDateTimeConverter + public sealed class JsonConverterDateOnly : System.Text.Json.Serialization.JsonConverter { - /// - /// 构造函数 - /// - /// - public DateTimeConverter(string format) : base() + public string Format { get; set; } + public JsonConverterDateOnly() { - base.DateTimeFormat = format; + this.Format = "yyyy-MM-dd"; + } + public JsonConverterDateOnly(string format) + { + if (format == null) throw new ArgumentNullException("format"); + Format = format; + } + public override DateOnly Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) + { + return DateOnly.Parse(reader.GetString()); + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, DateOnly value, System.Text.Json.JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(Format)); + } + } + + /// + /// 专为 .net6 提供 + /// + public sealed class JsonConverterTimeOnly : System.Text.Json.Serialization.JsonConverter + { + public string Format { get; set; } + public JsonConverterTimeOnly() + { + this.Format = "HH:mm:ss.fffffff"; + } + public JsonConverterTimeOnly(string format) + { + if (format == null) throw new ArgumentNullException("format"); + Format = format; + } + public override TimeOnly Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) + { + return TimeOnly.Parse(reader.GetString()); + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, TimeOnly value, System.Text.Json.JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(Format)); + } } + + public class JsonConverterDatetime : System.Text.Json.Serialization.JsonConverter + { + public string Format { get; set; } + public JsonConverterDatetime(string format) + { + if (format == null) throw new ArgumentNullException("format"); + Format = format; + } + public override DateTime Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) + { + return DateTime.Parse(reader.GetString()); + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, DateTime value, System.Text.Json.JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(Format)); + } + } + + public class JsonConverterDateTimeOffset : System.Text.Json.Serialization.JsonConverter + { + public string Format { get; set; } + public JsonConverterDateTimeOffset(string format) + { + if (format == null) throw new ArgumentNullException("format"); + Format = format; + } + public override DateTimeOffset Read(ref System.Text.Json.Utf8JsonReader reader, Type typeToConvert, System.Text.Json.JsonSerializerOptions options) + { + return DateTimeOffset.Parse(reader.GetString()); + } + + public override void Write(System.Text.Json.Utf8JsonWriter writer, DateTimeOffset value, System.Text.Json.JsonSerializerOptions options) + { + writer.WriteStringValue(value.ToString(Format)); + } + } + } diff --git a/src/DotNetCommon.Core/Serialize/NumberConverter.cs b/src/DotNetCommon.Core/Serialize/NumberConverter.cs deleted file mode 100644 index f490210b75c00cf05e269b8cb75c58cd8462d2f2..0000000000000000000000000000000000000000 --- a/src/DotNetCommon.Core/Serialize/NumberConverter.cs +++ /dev/null @@ -1,172 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; - -namespace DotNetCommon.Serialize -{ - /// - /// 大数据类型序列化器,支持将long/float/double/decimal转成字符串,定义在属性上比较方便([JsonConverter(typeof(NumberConverter), NumberConverterShip.Int64)]) - /// - public sealed class NumberConverter : JsonConverter - { - /// - /// 转换成字符串的类型 - /// - private readonly NumberConverterShip _ship; - - /// - /// 大数据json序列化重写实例化 - /// - public NumberConverter() - { - _ship = (NumberConverterShip)0xFF; - } - - /// - /// 大数据json序列化重写实例化 - /// - /// 转换成字符串的类型 - public NumberConverter(NumberConverterShip ship) - { - _ship = ship; - } - - /// - /// - /// 确定此实例是否可以转换指定的对象类型。 - /// - /// 对象的类型。 - /// 如果此实例可以转换指定的对象类型,则为:true,否则为:false - public override bool CanConvert(Type objectType) - { - var typecode = Type.GetTypeCode(objectType.Name.Equals("Nullable`1") ? objectType.GetGenericArguments().First() : objectType); - switch (typecode) - { - case TypeCode.Decimal: - return (_ship & NumberConverterShip.Decimal) == NumberConverterShip.Decimal; - case TypeCode.Double: - return (_ship & NumberConverterShip.Double) == NumberConverterShip.Double; - case TypeCode.Int64: - return (_ship & NumberConverterShip.Int64) == NumberConverterShip.Int64; - case TypeCode.UInt64: - return (_ship & NumberConverterShip.UInt64) == NumberConverterShip.UInt64; - case TypeCode.Single: - return (_ship & NumberConverterShip.Single) == NumberConverterShip.Single; - default: return false; - } - } - - /// - /// - /// 读取对象的JSON表示。 - /// - /// 中读取。 - /// 对象的类型。 - /// 正在读取的对象的现有值。 - /// 调用的序列化器实例。 - /// 对象值。 - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - return AsType(reader.Value.ToString(), objectType); - } - - /// - /// 字符串格式数据转其他类型数据 - /// - /// 输入的字符串 - /// 目标格式 - /// 转换结果 - public static object AsType(string input, Type destinationType) - { - try - { - var converter = TypeDescriptor.GetConverter(destinationType); - if (converter.CanConvertFrom(typeof(string))) - { - return converter.ConvertFrom(null, null, input); - } - - converter = TypeDescriptor.GetConverter(typeof(string)); - if (converter.CanConvertTo(destinationType)) - { - return converter.ConvertTo(null, null, input, destinationType); - } - } - catch - { - return null; - } - return null; - } - - /// - /// - /// 写入对象的JSON表示形式。 - /// - /// 要写入的 。 - /// 要写入对象值 - /// 调用的序列化器实例。 - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value == null) - { - writer.WriteNull(); - } - else - { - var objectType = value.GetType(); - var typeCode = Type.GetTypeCode(objectType.Name.Equals("Nullable`1") ? objectType.GetGenericArguments().First() : objectType); - switch (typeCode) - { - case TypeCode.Decimal: - writer.WriteValue(((decimal)value).ToString("f6")); - break; - case TypeCode.Double: - writer.WriteValue(((double)value).ToString("f4")); - break; - case TypeCode.Single: - writer.WriteValue(((float)value).ToString("f2")); - break; - default: - writer.WriteValue(value.ToString()); - break; - } - } - } - } - - /// - /// 转换成字符串的类型 - /// - [Flags] - public enum NumberConverterShip - { - /// - /// 长整数 - /// - Int64 = 1, - - /// - /// 无符号长整数 - /// - UInt64 = 2, - - /// - /// 浮点数 - /// - Single = 4, - - /// - /// 双精度浮点数 - /// - Double = 8, - - /// - /// 大数字 - /// - Decimal = 16 - } -} diff --git a/src/DotNetCommon.Core/Serialize/PrimitiveConvertor.cs b/src/DotNetCommon.Core/Serialize/PrimitiveConvertor.cs deleted file mode 100644 index fad7ade71d39cc1a1e1c5db3d3343cc2d97e1ad6..0000000000000000000000000000000000000000 --- a/src/DotNetCommon.Core/Serialize/PrimitiveConvertor.cs +++ /dev/null @@ -1,193 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; -using System.ComponentModel; -using System.Linq; -using System.Text; - -namespace DotNetCommon.Serialize -{ - /// - /// 接管c#基元类型转换(bool、char、byte、short/int/long/float/double/decimal - /// - public class PrimitiveConvertor : JsonConverter - { - private readonly bool isLongToString; - private readonly bool isAllToString; - private readonly int? allNumDigit; - private readonly int? decimalDigit; - - /// - /// 构造函数 - /// - /// 是否将所有支持的数据类型转换为字符串 - /// 是否将long类型转换为字符串 - /// 将所有的数字进行四舍五入后保留的小数位数 - /// 仅针对decimal数据类型进行四舍五入后保留的小数位数 - public PrimitiveConvertor(bool isLongToString = false, bool isAllToString = false, int? allNumDigit = null, int? decimalDigit = null) - { - this.isLongToString = isLongToString; - this.isAllToString = isAllToString; - this.allNumDigit = allNumDigit; - this.decimalDigit = decimalDigit; - } - - /// - /// 是否可以转换指定的数据类型 - /// - /// - /// - public override bool CanConvert(Type objectType) - { - var typecode = Type.GetTypeCode(objectType.Name.Equals("Nullable`1") ? objectType.GetGenericArguments().First() : objectType); - switch (typecode) - { - case TypeCode.Boolean: - case TypeCode.Char: - case TypeCode.SByte: - case TypeCode.Byte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.Single: - case TypeCode.Double: - case TypeCode.Decimal: - return true; - default: return false; - } - } - - /// - /// 反序列化json - /// - /// - /// - /// - /// - /// - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - return AsType(reader.Value?.ToString(), objectType); - } - - /// - /// 字符串格式数据转其他类型数据 - /// - /// 输入的字符串 - /// 目标格式 - /// 转换结果 - public static object AsType(string input, Type destinationType) - { - try - { - var converter = TypeDescriptor.GetConverter(destinationType); - if (converter.CanConvertFrom(typeof(string))) - { - return converter.ConvertFrom(null, null, input); - } - - converter = TypeDescriptor.GetConverter(typeof(string)); - if (converter.CanConvertTo(destinationType)) - { - return converter.ConvertTo(null, null, input, destinationType); - } - } - catch - { - return null; - } - return null; - } - - /// - /// 序列化指定数据类型 - /// - /// - /// - /// - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var typecode = Type.GetTypeCode(value?.GetType()); - switch (typecode) - { - case TypeCode.Boolean: - case TypeCode.Char: - case TypeCode.SByte: - case TypeCode.Byte: - case TypeCode.Int16: - case TypeCode.UInt16: - case TypeCode.Int32: - case TypeCode.UInt32: - { - if (isAllToString) writer.WriteValue(value?.ToString()); - else writer.WriteValue(value); - break; - } - case TypeCode.Int64: - case TypeCode.UInt64: - { - if (isAllToString || isLongToString) writer.WriteValue(value?.ToString()); - else - { - writer.WriteValue(value); - } - break; - } - case TypeCode.Single: - { - float val = (float)value; - if (allNumDigit != null) - { - val = float.Parse(val.ToString("F" + allNumDigit)); - } - if (isAllToString) writer.WriteValue(val.ToString()); - else - { - writer.WriteValue(val); - }; - break; - } - case TypeCode.Double: - { - double val = (double)value; - if (allNumDigit != null) - { - val = double.Parse(val.ToString("F" + allNumDigit)); - } - if (isAllToString) writer.WriteValue(val.ToString()); - else - { - writer.WriteValue(val); - }; - break; - } - case TypeCode.Decimal: - { - decimal val = (decimal)value; - if (decimalDigit != null) - { - val = decimal.Parse(val.ToString("F" + decimalDigit)); - } - else if (allNumDigit != null) - { - val = decimal.Parse(val.ToString("F" + allNumDigit)); - } - if (isAllToString) writer.WriteValue(val.ToString()); - else - { - writer.WriteValue(val); - }; - break; - } - default: - { - writer.WriteValue(value); - break; - } - } - } - } -} diff --git a/src/DotNetCommon/RoslynMapper.cs b/src/DotNetCommon/RoslynMapper.cs index 214ba5b1df1079ea03ef7fd3f12bf1ad83d5e478..12f859a4ebda9d0ee1e8c8a576bd532124fbefc8 100644 --- a/src/DotNetCommon/RoslynMapper.cs +++ b/src/DotNetCommon/RoslynMapper.cs @@ -2,7 +2,6 @@ using DotNetCommon.Extensions; using DotNetCommon.Logger; using DotNetCommon.Serialize; -using Newtonsoft.Json; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -185,7 +184,6 @@ namespace DotNetCommon "System.IO", "System.Collections", "System.Collections.Generic", - "Newtonsoft.Json", "DotNetCommon.Serialize" }; diff --git a/tests/DeepClonePerformanceTest/DeepClonePerformanceTest.csproj b/tests/DeepClonePerformanceTest/DeepClonePerformanceTest.csproj index 2c6d7bf19a88914c7892d2136812f6f9475a1001..99fa14dca50ed5483ae5e8db1735b83add7494d6 100644 --- a/tests/DeepClonePerformanceTest/DeepClonePerformanceTest.csproj +++ b/tests/DeepClonePerformanceTest/DeepClonePerformanceTest.csproj @@ -7,6 +7,10 @@ enable + + + + diff --git a/tests/DotNetCommon.Test/CompressHelperTests.cs b/tests/DotNetCommon.Test/CompressHelperTests.cs index e7edde7b420bf3c89e34c26cee9d78106f951727..b6c8cb055435aaa20e49263b00ed4d3a8ad64dda 100644 --- a/tests/DotNetCommon.Test/CompressHelperTests.cs +++ b/tests/DotNetCommon.Test/CompressHelperTests.cs @@ -43,7 +43,7 @@ namespace DotNetCommon.Test File.AppendAllText(Path.Combine(testfolderPath, "testsubfolder2", "testsubfolder-suba.txt"), "我是testsubfolder-suba.txt"); Directory.CreateDirectory(Path.Combine(testfolderPath, "testemptysubfolder")); } - [Test] + public void UnCompressTests() { var destDirPath = Path.Combine(rootPath, "testcompress_stream.zip"); @@ -85,7 +85,6 @@ namespace DotNetCommon.Test Directory.Delete(destDirPath, true); } - [Test] public void CompressStreamTests() { var destFilePath = Path.Combine(rootPath, "testcompress_stream.zip"); @@ -112,7 +111,6 @@ namespace DotNetCommon.Test File.ReadAllText(Path.Combine(destUnZipFolder, "testfolder-a.txt")).ShouldBe("我是testfolder-a.txt"); } - [Test] public void CompressFilesTests() { var destFilePath = Path.Combine(rootPath, "testcompress_stream.zip"); @@ -133,7 +131,6 @@ namespace DotNetCommon.Test File.ReadAllText(Path.Combine(destUnZipFolder, "testfolder-a.txt")).ShouldBe("我是testfolder-a.txt"); } - [Test] public void CompressZipFolderTests() { var destFilePath = Path.Combine(rootPath, "testcompress_stream.zip"); @@ -152,7 +149,6 @@ namespace DotNetCommon.Test File.ReadAllText(Path.Combine(destUnZipFolder, "testsubfolder2/testsubfolder-suba.txt")).ShouldBe("我是testsubfolder-suba.txt"); } - [Test] public void CompressZipFolderTests2() { var destFilePath = Path.Combine(rootPath, "testcompress_stream.zip"); @@ -167,7 +163,6 @@ namespace DotNetCommon.Test File.ReadAllText(Path.Combine(destUnZipFolder, "testfolder/testfolder-a.txt")).ShouldBe("我是testfolder-a.txt"); } - [Test] public void CompressZipFolderContentTests() { var destFilePath = Path.Combine(rootPath, "testcompress_stream.zip"); @@ -181,5 +176,16 @@ namespace DotNetCommon.Test File.ReadAllText(Path.Combine(destUnZipFolder, "testsubfolder/testsubfolder-suba.txt")).ShouldBe("我是testsubfolder-suba.txt"); File.ReadAllText(Path.Combine(destUnZipFolder, "testfolder-a.txt")).ShouldBe("我是testfolder-a.txt"); } + + [Test] + public void TestFlow() + { + CompressZipFolderContentTests(); + CompressZipFolderTests2(); + CompressZipFolderTests(); + CompressFilesTests(); + CompressStreamTests(); + UnCompressTests(); + } } } diff --git a/tests/DotNetCommon.Test/Extensions/JsonExtensionTests.cs b/tests/DotNetCommon.Test/Extensions/JsonExtensionTests.cs index 4880c8bbd20cda454de3f383e0988247bc4b8aec..731e92fb9ad47d16fc734e982798e7727f6381fb 100644 --- a/tests/DotNetCommon.Test/Extensions/JsonExtensionTests.cs +++ b/tests/DotNetCommon.Test/Extensions/JsonExtensionTests.cs @@ -23,10 +23,10 @@ namespace DotNetCommon.Test.Extensions Birth = DateTime.Now }; //{"Id":"1","Age":18,"Name":"小明","Birth":"2021-05-25 21:04:43"} - var json = person.ToJsonFast(isLongToString: true); + var json = person.ToJsonFast(number2String: true); //{"Id":"1","Age":"18","Name":"小明","Birth":"2021-05-25"} - json = person.ToJsonFast(isAllToString: true, dateFormatString: "yyyy-MM-dd"); + json = person.ToJsonFast(number2String: true, dateFormatString: "yyyy-MM-dd"); } diff --git a/tests/DotNetCommon.Test/Extensions/ObjectTests_DeepClone.cs b/tests/DotNetCommon.Test/Extensions/ObjectTests_DeepClone.cs index edd3a0018cd435c48e4c8869fec8cb3647683d40..555d0cb1d8dafbef948f0d07bfd88656ed16de51 100644 --- a/tests/DotNetCommon.Test/Extensions/ObjectTests_DeepClone.cs +++ b/tests/DotNetCommon.Test/Extensions/ObjectTests_DeepClone.cs @@ -13,6 +13,8 @@ using System.Diagnostics; using System.Numerics; using System.ComponentModel; using System.Drawing; +using System.Text.Json.Nodes; +using System.Text.Json; namespace DotNetCommon.Test.Extensions { @@ -27,6 +29,34 @@ namespace DotNetCommon.Test.Extensions objNew.ShouldBeNull(); } + [Test] + public void Test_JObjectJArray() + { + var obj = new { Id = 1, Name = "小明" }.ToJson().ToObject() as object; + var obj2 = obj.DeepClone(); + Assert.IsFalse(obj2 == obj); + + var arr = new[] { new { Id = 1, Name = "小明" } }.ToJson().ToObject() as object; + obj2 = arr.DeepClone(); + Assert.IsFalse(obj2 == arr); + } + + [Test] + public void Test_JsonObjectJsonArrayJsonDocument() + { + var obj = new { Id = 1, Name = "小明" }.ToJson().ToObject() as object; + var obj2 = obj.DeepClone(); + Assert.IsFalse(obj2 == obj); + + var arr = new[] { new { Id = 1, Name = "小明" } }.ToJson().ToObject() as object; + obj2 = arr.DeepClone(); + Assert.IsFalse(obj2 == arr); + + var doc = new[] { new { Id = 1, Name = "小明" } }.ToJson().ToObject() as object; + obj2 = doc.DeepClone(); + Assert.IsFalse(obj2 == arr); + } + [Test] public void Test_CloneSimple() { @@ -734,6 +764,7 @@ namespace DotNetCommon.Test.Extensions Assert.IsTrue(list != newList); Assert.IsTrue(newList[0] != list[0]); Assert.IsTrue(newList[1] != list[1]); + newList[0]["Id"].Value().ShouldBe(1); newList[0]["Name"].Value().ShouldBe("小明"); diff --git a/tests/DotNetCommon.Test/Extensions/StringExtensionsTests.cs b/tests/DotNetCommon.Test/Extensions/StringExtensionsTests.cs index 94361a6fdd3a057a8b8a311bb1aecd3f07708557..35aff928f83c283e6d6075a2764c31240bcb392f 100644 --- a/tests/DotNetCommon.Test/Extensions/StringExtensionsTests.cs +++ b/tests/DotNetCommon.Test/Extensions/StringExtensionsTests.cs @@ -6,6 +6,8 @@ using System.Linq; using System.Text; using DotNetCommon.Extensions; using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; +using System.Text.Json; namespace DotNetCommon.Test.Extensions { @@ -576,12 +578,34 @@ namespace DotNetCommon.Test.Extensions ] "; var jArray = json.ToObject(); - jArray.Count.ShouldBe(5); - jArray.Where(i => i.Type == JTokenType.Comment).Count().ShouldBe(2); - - jArray = json.ToObject(true); jArray.Count.ShouldBe(3); jArray.Where(i => i.Type == JTokenType.Comment).Count().ShouldBe(0); + + + var jsonaArray = json.ToObject(); + jsonaArray.Count.ShouldBe(3); + + var jsonDoc = json.ToObject(); + jsonDoc.RootElement.ValueKind.ShouldBe(JsonValueKind.Array); + jsonDoc.RootElement.GetArrayLength().ShouldBe(3); + + var json2 = @" +{ + ""name"":""小明"", + ""age"":18, + ""birth"":""1998-02-01"", + //""score:"":98.5, + /*""ref"":null, + ""desc"":undefined*/ +} +"; + var jobj = json2.ToObject(); + jobj.Count.ShouldBe(3); + var jsonObject = json2.ToObject(); + jsonObject.Count.ShouldBe(3); + var jsonDocument = json2.ToObject(); + jsonDocument.RootElement.ValueKind.ShouldBe(JsonValueKind.Object); + jsonDocument.RootElement.EnumerateObject().Count().ShouldBe(3); } } diff --git a/tests/DotNetCommon.Test/JsonHelperTests.cs b/tests/DotNetCommon.Test/JsonHelperTests.cs index b58ce8413607f431275cbc6be1793d3e2ec98eeb..4affa03fba5be31096fbb26e8b9c71fbfba36a2e 100644 --- a/tests/DotNetCommon.Test/JsonHelperTests.cs +++ b/tests/DotNetCommon.Test/JsonHelperTests.cs @@ -5,6 +5,8 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; namespace DotNetCommon.Test { @@ -68,7 +70,6 @@ namespace DotNetCommon.Test ""birth"":""1998-02-01"", ""score:"":98.5, ""ref"":null, - ""desc"":undefined }"; var result = JsonHelper.Format(json); diff --git a/tests/DotNetCommon.Test/RegistryHelperTests.cs b/tests/DotNetCommon.Test/RegistryHelperTests.cs index 82b3243132a14eeebb4cd01e912eefb164254448..03f4240089abbf81140a65590f937904811c6707 100644 --- a/tests/DotNetCommon.Test/RegistryHelperTests.cs +++ b/tests/DotNetCommon.Test/RegistryHelperTests.cs @@ -2,11 +2,13 @@ using NUnit.Framework; using System; using System.Collections.Generic; +using System.Runtime.Versioning; using System.Text; using helper = DotNetCommon.RegistryHelper; namespace DotNetCommon.Test { + [SupportedOSPlatform("Windows")] [TestFixture] public class RegistryHelperTests { diff --git a/tests/DotNetCommon.Test/Serialize/SerializeTests.cs b/tests/DotNetCommon.Test/Serialize/SerializeTests.cs index 259588f6cfbba511013925f01f56f0d46c51a611..f8dcb7a05934d4500e7265447c950dddba65c932 100644 --- a/tests/DotNetCommon.Test/Serialize/SerializeTests.cs +++ b/tests/DotNetCommon.Test/Serialize/SerializeTests.cs @@ -7,6 +7,9 @@ using System; using System.Collections.Generic; using System.Text; using DotNetCommon.Extensions; +using System.ComponentModel; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Serialization; namespace DotNetCommon.Test.Serialize { @@ -24,10 +27,13 @@ namespace DotNetCommon.Test.Serialize Id = long.MaxValue, Name = "小明", State = EnumState.Close, - Birth = DateTime.Now, + Birth = DateTime.Parse("2023-06-04 15:52:01.1234567 +08:00"), Addr = "天明路" }; var str = obj.ToJson(); + str.ShouldBe("{\"Id\":9223372036854775807,\"Birth\":\"2023-06-04T15:52:01.1234567+08:00\",\"Addr\":\"天明路\",\"Name\":\"小明\",\"StudentId\":0,\"ClassId\":null,\"State\":1}"); + var str2 = str.ToObject().ToJson(); + str2.ShouldBe(str); } /// @@ -75,28 +81,42 @@ namespace DotNetCommon.Test.Serialize PString = "abc", - PDateTime = DateTime.Now, - PDateTimeNull = DateTime.UtcNow, + PDateTime = DateTime.Parse("2023-06-04 16:40:17"), + PDateTimeNull = DateTime.Parse("2023-06-04 16:40:17"), }; - var str = Newtonsoft.Json.JsonConvert.SerializeObject(person, Formatting.Indented); - var json = Newtonsoft.Json.JsonConvert.SerializeObject(person, Formatting.Indented, new JsonSerializerSettings() + var json = person.ToJsonFast(); + json.ShouldBe("{\"PByte\":1,\"PByteNull\":2,\"PSByte\":-1,\"PSByteNull\":-2,\"PShort\":3,\"PShortNull\":4,\"PUShort\":5,\"PUShortNull\":6,\"PInt\":7,\"PUInt\":8,\"PIntNull\":9,\"PUIntNull\":10,\"PLong\":11,\"PULong\":12,\"PLongNull\":13,\"PULongNull\":14,\"PFloat\":15.1,\"PUFloat\":16.123457,\"PDouble\":17.123456789,\"PDoubleNull\":18.123456789012344,\"PDecimal\":19.12345678901234567890,\"PDecimalNull\":20.123456789012345678901234568,\"PChar\":\"a\",\"PCharNull\":\"b\",\"PBool\":false,\"PBoolNull\":null,\"PString\":\"abc\",\"PDateTime\":\"2023-06-04T16:40:17\",\"PDateTimeNull\":\"2023-06-04T16:40:17\",\"State\":0}"); + + var obj = new TestJObject { - Converters = new List() - { - new PrimitiveConvertor() - } - }); - str.ShouldBe(json); + Id = 1, + Name = "小明", + BirthDay = DateTime.Parse("2023-06-04 16:43:01"), + State = EnumState.Open + }; + + json = obj.ToJson(); + json.ShouldBe("{\"Id\":1,\"Name\":\"小明\",\"BirthDay\":\"2023-06-04T16:43:01\",\"NullObj\":null,\"State\":2}"); + var json2 = json.ToObject().ToJsonFast(dateFormatString: "yyyy-MM-dd", IgnoreNull: true, enum2String: true, lowerCamelCase: true, isIntend: true); + json2.ShouldBe("{\r\n \"Id\": 1,\r\n \"Name\": \"小明\",\r\n \"BirthDay\": \"2023-06-04\",\r\n \"NullObj\": null,\r\n \"State\": 2\r\n}"); + } + + public class TestJObject + { + public int Id { get; set; } + public string Name { get; set; } + public DateTime BirthDay { get; set; } + public object NullObj { get; set; } + public EnumState State { get; set; } } #region Model1 & NumberConverter、DateTimeConverter public class Person { - [JsonConverter(typeof(NumberConverter), NumberConverterShip.Int64)] public long Id { get; set; } - [JsonConverter(typeof(DateTimeConverter), "yyyy-MM-dd")] + //[JsonConverter(typeof(DateTimeConverter), "yyyy-MM-dd")] public DateTime Birth { get; set; } [JsonIgnore] diff --git a/tests/MapperPerformanceTest/MapperPerformanceTest.csproj b/tests/MapperPerformanceTest/MapperPerformanceTest.csproj index 0c5144a0a5479e18a21f8c63ced0cd2fe80906e4..23cd0a198bcb8eabbae16dd77eb1ed2faccb04d7 100644 --- a/tests/MapperPerformanceTest/MapperPerformanceTest.csproj +++ b/tests/MapperPerformanceTest/MapperPerformanceTest.csproj @@ -6,7 +6,8 @@ - + +