From 726383ef2d6a0005565980097743d12039ab1577 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Sat, 12 Sep 2020 19:49:41 +0800 Subject: [PATCH 01/15] =?UTF-8?q?=E5=AD=98=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CkTools/CkTools.sln | 14 ++ .../Extensions/ObjectExtensions.cs | 26 +- .../BaseType/DictionaryExtensions.cs | 5 - .../BaseType/ObjectExtensions.cs | 17 +- .../BaseType/StringExtensions.cs | 104 ++++---- .../Aop/LogicChainStepAttribute.cs | 132 ++++++++++ CkTools/Src/CkTools.Nova/CkTools.Nova.csproj | 19 ++ CkTools/Src/CkTools.Nova/Entity/NullResult.cs | 9 + .../Entity/StepContext.Static.Funcation.cs | 94 +++++++ .../Src/CkTools.Nova/Entity/StepContext.cs | 16 ++ .../Entity/StepContextExtension.cs | 28 +++ .../CkTools.Nova/Entity/StepContextGeneric.cs | 42 ++++ CkTools/Src/CkTools.Nova/Entity/StepEntity.cs | 32 +++ .../Factory/ILogicalChainFactory.cs | 32 +++ .../Factory/LogicalChainFactory.cs | 183 ++++++++++++++ .../CkTools.Nova/Helper/LogicalChainHelper.cs | 166 +++++++++++++ .../Src/CkTools.Nova/LogicChain/EndStep.cs | 15 ++ .../CkTools.Nova/LogicChain/EndStepGeneric.cs | 16 ++ CkTools/Src/CkTools.Nova/LogicChain/IStep.cs | 31 +++ .../CkTools.Nova/LogicChain/IStepGeneric.cs | 23 ++ .../Src/CkTools.Nova/LogicChain/StepBase.cs | 44 ++++ .../LogicChain/StepBaseGeneric.cs | 44 ++++ .../Middleware/LogicChainExtension.cs | 42 ++++ .../CkTools.Nova/Middleware/TaskMwHelper.cs | 35 +++ CkTools/Src/SDKPulishNuget.targets | 2 +- CkTools/Test/CKTols.FP.Test/Maybe`1Test.cs | 6 + .../BaseType/IEnumerableExtensionsTest.cs | 2 +- .../Extensions/EnumerableExtensions.cs | 81 ++++++ .../Extensions/ObjectExtensionsTest.cs | 139 +++++++++++ .../Aop/LogicChainStepAttributeTest.cs | 85 +++++++ .../CkTools.Nova.Test.csproj | 12 + .../Test/CkTools.Nova.Test/DI_Test/DI_Test.cs | 105 ++++++++ .../Factory/LogicalChainFactoryTest.cs | 12 + .../LogicChain/LogicalChainHelperTest.cs | 234 ++++++++++++++++++ .../CkTools.Nova.Test/TestModel/TestConfig.cs | 12 + .../CkTools.Nova.Test/TestModel/TestResult.cs | 8 + .../TestModel/TestTaskEnum.cs | 16 ++ .../TestModel/Test_A_Step.cs | 36 +++ .../TestModel/Test_B_Step.cs | 33 +++ .../TestModel/Test_C_Step.cs | 42 ++++ 40 files changed, 1913 insertions(+), 81 deletions(-) create mode 100644 CkTools/Src/CkTools.Nova/Aop/LogicChainStepAttribute.cs create mode 100644 CkTools/Src/CkTools.Nova/CkTools.Nova.csproj create mode 100644 CkTools/Src/CkTools.Nova/Entity/NullResult.cs create mode 100644 CkTools/Src/CkTools.Nova/Entity/StepContext.Static.Funcation.cs create mode 100644 CkTools/Src/CkTools.Nova/Entity/StepContext.cs create mode 100644 CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs create mode 100644 CkTools/Src/CkTools.Nova/Entity/StepContextGeneric.cs create mode 100644 CkTools/Src/CkTools.Nova/Entity/StepEntity.cs create mode 100644 CkTools/Src/CkTools.Nova/Factory/ILogicalChainFactory.cs create mode 100644 CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs create mode 100644 CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs create mode 100644 CkTools/Src/CkTools.Nova/LogicChain/EndStep.cs create mode 100644 CkTools/Src/CkTools.Nova/LogicChain/EndStepGeneric.cs create mode 100644 CkTools/Src/CkTools.Nova/LogicChain/IStep.cs create mode 100644 CkTools/Src/CkTools.Nova/LogicChain/IStepGeneric.cs create mode 100644 CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs create mode 100644 CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs create mode 100644 CkTools/Src/CkTools.Nova/Middleware/LogicChainExtension.cs create mode 100644 CkTools/Src/CkTools.Nova/Middleware/TaskMwHelper.cs create mode 100644 CkTools/Test/CkTools.Abstraction.Test/Extensions/EnumerableExtensions.cs create mode 100644 CkTools/Test/CkTools.Abstraction.Test/Extensions/ObjectExtensionsTest.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/CkTools.Nova.Test.csproj create mode 100644 CkTools/Test/CkTools.Nova.Test/DI_Test/DI_Test.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/Factory/LogicalChainFactoryTest.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/LogicChain/LogicalChainHelperTest.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/TestModel/TestConfig.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/TestModel/TestResult.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/TestModel/TestTaskEnum.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/TestModel/Test_A_Step.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/TestModel/Test_B_Step.cs create mode 100644 CkTools/Test/CkTools.Nova.Test/TestModel/Test_C_Step.cs diff --git a/CkTools/CkTools.sln b/CkTools/CkTools.sln index e65c386b..71d254e5 100644 --- a/CkTools/CkTools.sln +++ b/CkTools/CkTools.sln @@ -31,6 +31,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CkTools.Abstraction.Test", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CKTools.BaseExtensions.Test", "Test\CKTools.BaseExtensions.Test\CKTools.BaseExtensions.Test.csproj", "{2C2E3545-4B13-4746-A702-0F999240818F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CkTools.Nova", "Src\CkTools.Nova\CkTools.Nova.csproj", "{6713F0C2-BB89-463B-AEB6-00BBFEC6DE00}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CkTools.Nova.Test", "Test\CkTools.Nova.Test\CkTools.Nova.Test.csproj", "{5837DBA3-47A0-43BF-9346-F2C8878F6AC4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +73,14 @@ Global {2C2E3545-4B13-4746-A702-0F999240818F}.Debug|Any CPU.Build.0 = Debug|Any CPU {2C2E3545-4B13-4746-A702-0F999240818F}.Release|Any CPU.ActiveCfg = Release|Any CPU {2C2E3545-4B13-4746-A702-0F999240818F}.Release|Any CPU.Build.0 = Release|Any CPU + {6713F0C2-BB89-463B-AEB6-00BBFEC6DE00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6713F0C2-BB89-463B-AEB6-00BBFEC6DE00}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6713F0C2-BB89-463B-AEB6-00BBFEC6DE00}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6713F0C2-BB89-463B-AEB6-00BBFEC6DE00}.Release|Any CPU.Build.0 = Release|Any CPU + {5837DBA3-47A0-43BF-9346-F2C8878F6AC4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5837DBA3-47A0-43BF-9346-F2C8878F6AC4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5837DBA3-47A0-43BF-9346-F2C8878F6AC4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5837DBA3-47A0-43BF-9346-F2C8878F6AC4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -82,6 +94,8 @@ Global {759F7D6B-B88F-4B90-8DA6-9F6E8DD61DEC} = {D80CD124-05E6-4F2F-ADCD-328ACACA04E5} {B9045104-1DE3-40C9-9DF2-7E896AEFE751} = {D80CD124-05E6-4F2F-ADCD-328ACACA04E5} {2C2E3545-4B13-4746-A702-0F999240818F} = {D80CD124-05E6-4F2F-ADCD-328ACACA04E5} + {6713F0C2-BB89-463B-AEB6-00BBFEC6DE00} = {D3146C29-9318-45EC-B9BA-1EC7653421FB} + {5837DBA3-47A0-43BF-9346-F2C8878F6AC4} = {D80CD124-05E6-4F2F-ADCD-328ACACA04E5} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {AB04A57E-6447-4E76-862D-5D1B1638F2B6} diff --git a/CkTools/Src/CkTools.Abstraction/Extensions/ObjectExtensions.cs b/CkTools/Src/CkTools.Abstraction/Extensions/ObjectExtensions.cs index 329f4069..c73b36a9 100644 --- a/CkTools/Src/CkTools.Abstraction/Extensions/ObjectExtensions.cs +++ b/CkTools/Src/CkTools.Abstraction/Extensions/ObjectExtensions.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Threading.Tasks; namespace System { @@ -14,7 +15,8 @@ public static class ObjectExtensions /// 要检查的对象 /// 抛出异常时,显示的参数名 /// 为null时抛出 - public static void CheckNullWithException(this T obj, string paramName) + public static void CheckNullWithException(this T? obj, string paramName) + where T : class { if (obj == null) throw new ArgumentNullException(paramName); } @@ -27,7 +29,8 @@ public static void CheckNullWithException(this T obj, string paramName) /// 抛出异常时,显示的参数名 /// 抛出异常时,显示的错误信息 /// 为null时抛出 - public static void CheckNullWithException(this T obj, string paramName, string message) + public static void CheckNullWithException(this T? obj, string paramName, string message) + where T : class { if (obj == null) throw new ArgumentNullException(paramName, message); } @@ -38,7 +41,7 @@ public static void CheckNullWithException(this T obj, string paramName, strin /// 要检查的对象 /// 抛出异常时,显示的参数名 /// 为null或emtpy时抛出 - public static void CheckNullOrEmptyWithException(this IEnumerable obj, string paramName) + public static void CheckNullOrEmptyWithException(this IEnumerable? obj, string paramName) { if (obj.IsNullOrEmpty()) throw new ArgumentNullException(paramName); } @@ -50,7 +53,7 @@ public static void CheckNullOrEmptyWithException(this IEnumerable obj, string pa /// 抛出异常时,显示的参数名 /// 抛出异常时,显示的错误信息 /// 为null或emtpy时抛出 - public static void CheckNullOrEmptyWithException(this IEnumerable obj, string paramName, string message) + public static void CheckNullOrEmptyWithException(this IEnumerable? obj, string paramName, string message) { if (obj.IsNullOrEmpty()) throw new ArgumentNullException(paramName, message); } @@ -108,7 +111,7 @@ public static bool IsNull(this object value) /// 对象类型 /// 要判断的数组 /// 判断结果,null或空数组返回true,否则返回false - public static bool IsNullOrEmpty(this T[] value) + public static bool IsNullOrEmpty(this T[]? value) { return value == null || value.Length == 0; } @@ -140,7 +143,7 @@ public static bool IsNullOrEmpty(this IDictionary value) /// /// 要判断的字典 /// 判断结果,null或空枚举器返回true,否则返回false - public static bool IsNullOrEmpty(this IEnumerable value) + public static bool IsNullOrEmpty(this IEnumerable? value) { return value == null || !value.GetEnumerator().MoveNext(); @@ -217,5 +220,16 @@ public static bool IsNotNullOrEmpty(this IEnumerable value) } #endregion IsNotNull and IsNotNullOrEmpty + + /// + /// 转换为类型 + /// + /// + /// + /// + public static Task ToTask(this TResult obj) + { + return Task.FromResult(obj); + } } } \ No newline at end of file diff --git a/CkTools/Src/CkTools.BaseExtensions/BaseType/DictionaryExtensions.cs b/CkTools/Src/CkTools.BaseExtensions/BaseType/DictionaryExtensions.cs index 8d50832b..b92656b7 100644 --- a/CkTools/Src/CkTools.BaseExtensions/BaseType/DictionaryExtensions.cs +++ b/CkTools/Src/CkTools.BaseExtensions/BaseType/DictionaryExtensions.cs @@ -15,7 +15,6 @@ public static TValue GetOrDefault( TKey key, TValue defaultValue = default) { - key.CheckNullWithException(nameof(key)); if (valuePairs.IsNullOrEmpty()) { return defaultValue; } bool isExist = valuePairs.TryGetValue(key, out TValue value); @@ -37,8 +36,6 @@ public static bool TryAdd( TKey key, TValue value) { - key.CheckNullWithException(nameof(key)); - value.CheckNullWithException(nameof(value)); valuePairs.CheckNullWithException(nameof(valuePairs)); bool isExist = valuePairs.ContainsKey(key); @@ -83,7 +80,6 @@ public static TValue GetOrAdd( Func factory) { - key.CheckNullWithException(nameof(key)); valuePairs.CheckNullWithException(nameof(valuePairs)); factory.CheckNullWithException(nameof(factory)); @@ -168,7 +164,6 @@ public static TValue AddOrUpdate( TValue value) { valuePairs.CheckNullWithException(nameof(valuePairs)); - value.CheckNullWithException(nameof(value)); if (valuePairs.ContainsKey(key)) { diff --git a/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs b/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs index 485f3b26..62471d57 100644 --- a/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs +++ b/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs @@ -65,7 +65,7 @@ public static string ToJsonExt(this T obj, Type type) #endregion Tojson - public static T DeepCopy(this T obj) + public static T? DeepCopy(this T obj) where T : class { string outPut = obj.ToJsonExt(); @@ -175,21 +175,6 @@ private static IEnumerable> GetAllPropertyValueIter #region 基础类型与Object之间的转换 - /// - /// 转换为byte[] - /// - /// - /// 编码格式,默认 - /// - public static byte[] ToBytes(this T source, Encoding? encoding = null) - { - source.CheckNullWithException(nameof(source)); - - string objStr = JsonConvert.SerializeObject(source, JsonSerializerSettingConst.StorageSetting); - encoding = encoding ?? Encoding.UTF8; - return objStr.ToBytes(encoding); - } - public static int ToInt32(this T str) where T : class { diff --git a/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs b/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs index 8b0600d1..d01d5750 100644 --- a/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs +++ b/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs @@ -27,7 +27,7 @@ public static T ToObjectExt( this string jsonStr, JsonSerializerSettings? jsonSerializerSettings = null) { - jsonSerializerSettings = jsonSerializerSettings ?? JsonSerializerSettingConst.DefaultSetting; + jsonSerializerSettings ??= JsonSerializerSettingConst.DefaultSetting; return JsonConvert.DeserializeObject(jsonStr, jsonSerializerSettings); } @@ -77,39 +77,6 @@ public static string ToCountryName(this string countryName) } }; - /// - /// 基础转换,转换失败时会报错 - /// - /// - /// 要转换的字符串 - /// 转换的方法 - /// 类型为 的值 - /// The parameter 'str' is invalid、Empty、Null - private static TValue BaseConvert( - this string str, - Func convert) - { - Func convertTemp = t => { emptyWithException(t); return convert(t); }; - return str.BaseConvert(convertTemp); - } - - /// - /// 基础转换,转换失败时会返回默认值 - /// - /// - /// 要转换的字符串 - /// 默认值 - /// 转换的方法 - /// 类型为 的值 - private static TValue TryBaseConvert( - this string str, - Func convert, - TValue defaultValue = default) - { - Func convertTemp = t => { emptyWithException(t); return convert(t); }; - return str.BaseConvertOrDefalut(defaultValue, convertTemp); - } - public static int ToInt32(this string str) { return str.BaseConvert(System.Convert.ToInt32); @@ -136,8 +103,8 @@ public static decimal ToDecimal(this string str) } public static decimal ToDecimalOrDefault( - this string str, - decimal defaultValue = 0.00M) + this string str, + decimal defaultValue = 0.00M) { return str.TryBaseConvert(System.Convert.ToDecimal, defaultValue); } @@ -148,29 +115,57 @@ public static double ToDouble(this string str) } public static double ToDoubleOrDefault( - this string str, - double defaultValue = 0.00) + this string str, + double defaultValue = 0.00) { return str.TryBaseConvert(System.Convert.ToDouble, defaultValue); } - #region TryToDateTimeOffset + public static long ToLong(this string str, long defaultValue = 0L) + { + return str.TryBaseConvert(TypeConvertDelegate.stringToLong, defaultValue); + } /// - /// 标准时间格式中包含的符号(用于和long区分使用) + /// 基础转换,转换失败时会报错 /// - private static string[] timeSysmbols = new string[] { ":", "+", "T", "Z", "-", "/" }; + /// + /// 要转换的字符串 + /// 转换的方法 + /// 类型为 的值 + /// The parameter 'str' is invalid、Empty、Null + private static TValue BaseConvert( + this string str, + Func convert) + { + Func convertTemp = t => { emptyWithException(t); return convert(t); }; + return str.BaseConvert(convertTemp); + } - private static DateTimeOffset TryToDateTimeOffsetBase(this string str, Func convert) + /// + /// 基础转换,转换失败时会返回默认值 + /// + /// + /// 要转换的字符串 + /// 默认值 + /// 转换的方法 + /// 类型为 的值 + private static TValue TryBaseConvert( + this string str, + Func convert, + TValue defaultValue = default) { - return str switch - { - string a when a.IsNullOrEmpty() => DateTimeOffset.MinValue, - var a when a.ContainsSymbol(timeSysmbols) => str.TryBaseConvert(TypeConvertDelegate.stringToDateTimeOffset), - _ => str.TryBaseConvert(convert)//匹配不上则为long - }; + Func convertTemp = t => { emptyWithException(t); return convert(t); }; + return str.BaseConvertOrDefalut(defaultValue, convertTemp); } + #region TryToDateTimeOffset + + /// + /// 标准时间格式中包含的符号(用于和long区分使用) + /// + private static string[] timeSysmbols = new string[] { ":", "+", "T", "Z", "-", "/" }; + public static DateTimeOffset TryToDateTimeOffset(this string str) { return str.TryBaseConvert(TypeConvertDelegate.stringToDateTimeOffset); @@ -196,13 +191,18 @@ public static DateTimeOffset TryToLocalDateTimeOffsetByMilliseconds(this string return str.TryToDateTimeOffsetBase(TypeConvertDelegate.longStringToLocalDateTimeOffsetByMilliseconds); } - #endregion TryToDateTimeOffset - - public static long ToLong(this string str, long defaultValue = 0L) + private static DateTimeOffset TryToDateTimeOffsetBase(this string str, Func convert) { - return str.TryBaseConvert(TypeConvertDelegate.stringToLong, defaultValue); + return str switch + { + string a when a.IsNullOrEmpty() => DateTimeOffset.MinValue, + var a when a.ContainsSymbol(timeSysmbols) => str.TryBaseConvert(TypeConvertDelegate.stringToDateTimeOffset), + _ => str.TryBaseConvert(convert)//匹配不上则为long + }; } + #endregion TryToDateTimeOffset + #endregion 基础类型与string之间的转换 /// diff --git a/CkTools/Src/CkTools.Nova/Aop/LogicChainStepAttribute.cs b/CkTools/Src/CkTools.Nova/Aop/LogicChainStepAttribute.cs new file mode 100644 index 00000000..03146ac5 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Aop/LogicChainStepAttribute.cs @@ -0,0 +1,132 @@ +using CkTools.Nova.Entity; +using CkTools.Nova.LogicChain; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Diagnostics.CodeAnalysis; + +namespace CkTools.Nova.Aop +{ + /// + /// 步骤链-自动注册标记 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Enum, Inherited = false, AllowMultiple = false)] + public class StepAttribute : Attribute + { + #region 构造方法 + + /// + /// 初始化一个实例 + /// + /// 步骤枚举值 + public StepAttribute([NotNull] object stepEnumValue) + : this(stepEnumValue, ServiceLifetime.Singleton) { } + + /// + /// 初始化一个实例 + /// + /// 步骤枚举值 + /// + /// 表示中的类型。 + /// + /// 如果你继承的是,建议指定此属性,提高代码阅读性. + /// + /// 如果你继承的是,则不用指定此属性,框架会自动赋值. + /// + public StepAttribute([NotNull] object stepEnumValue, Type contextResultType) + : this(stepEnumValue, contextResultType, ServiceLifetime.Singleton) { } + + /// + /// 初始化一个实例 + /// + /// 步骤枚举值 + /// + /// 表示在DI中的生命周期配置。默认为 + /// + public StepAttribute([NotNull] object stepEnumValue, ServiceLifetime lifetime) + : this(stepEnumValue, null, lifetime) { } + + /// + /// 初始化一个实例 + /// + /// 步骤枚举值 + /// + /// 表示中的类型。 + /// + /// 如果你继承的是,建议指定此属性,提高代码阅读性. + /// + /// 如果你继承的是,则不用指定此属性,框架会自动赋值. + /// + /// + /// 表示在DI中的生命周期配置。默认为 + /// + public StepAttribute( + [NotNull] object stepEnumValue, + Type? contextResultType, + ServiceLifetime lifetime) + { + #region 检测 + + stepEnumValue.CheckNullWithException(nameof(stepEnumValue)); + + if (stepEnumValue.GetType().IsEnum == false) + + { + throw new TypeAccessException($"{nameof(StepAttribute)} initialization need Enum type.{nameof(stepEnumValue)}'s type is {stepEnumValue.GetType().Name}"); + } + + #endregion 检测 + + this.StepEnumType = stepEnumValue.GetType(); + this.StepEnumOrder = (int)stepEnumValue; + + this.ContextResultType = contextResultType; + this.Lifetime = lifetime; + } + + #endregion 构造方法 + + /// + /// 实现步骤类上面的打的步骤枚举类型 + /// + public Type StepEnumType { get; } + + /// + /// 实现步骤类上面的打的步骤枚举值 + /// + public int StepEnumOrder { get; } + + /// + /// 表示中的类型 + /// + public Type? ContextResultType { get; set; } + + public Enum StepEnumValue { get; set; } + + /// + /// 代表步骤实现的生命周期 + /// + /// + /// 用来向IOC注册时指定作用域 + /// + public ServiceLifetime Lifetime { get; } + + /* + * todo:特性重构: + * + * 目标: + * 1. 无返回值的只需要打步骤枚举即可 + * 2. 有返回值的 + * 可以打在实现类上 + * 也可以打在返回结果的类型上面 + * + * 如果都有,以返回结果的类型上面为准(但是这一点最后可以询问下群里,那种会比较爽) + * + * + * 3.上面修改完成之后,需要修改UT,还有EndStep<>的获取。 + * + * + * 影响: 特性类要改名,2种情况的要分开了(可考虑要不要继承) + * 创建的工厂也需要修改,改查找的地方,然后判断用实现类的还是结果类上面的 + */ + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/CkTools.Nova.csproj b/CkTools/Src/CkTools.Nova/CkTools.Nova.csproj new file mode 100644 index 00000000..e6b5065f --- /dev/null +++ b/CkTools/Src/CkTools.Nova/CkTools.Nova.csproj @@ -0,0 +1,19 @@ + + + + + + netstandard2.1 + $(LibName)的逻辑链,在业务中使用中间件模式,可动态配置执行顺序,随意修改节点逻辑 + https://github.com/hjkl950217/learningTest + https://github.com/hjkl950217/learningTest + + + + + + + + + + \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Entity/NullResult.cs b/CkTools/Src/CkTools.Nova/Entity/NullResult.cs new file mode 100644 index 00000000..7689b3df --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Entity/NullResult.cs @@ -0,0 +1,9 @@ +namespace CkTools.Nova.Entity +{ + /// + /// 空类,用作框架操作无返回值的情况 + /// + public class NullResult + { + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Entity/StepContext.Static.Funcation.cs b/CkTools/Src/CkTools.Nova/Entity/StepContext.Static.Funcation.cs new file mode 100644 index 00000000..5bfdb976 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Entity/StepContext.Static.Funcation.cs @@ -0,0 +1,94 @@ +namespace CkTools.Nova.Entity +{ + //一些静态方法 + //类似微软一样,Task.XX() + public abstract partial class StepContext + { + /// + /// 一个,无于返回值的场景。 + /// + public static readonly NullResult DefualtNullResult = new NullResult(); + + #region 创建StepContext + + ///// + ///// (未启用)创建一个新的. + ///// 里面的数据初始化部分不会负责 + ///// + ///// + ///// 此功能需要配合自动注册,暂未开发 + ///// + ///// 上下文中返回的类型 + ///// DI实例 + ///// + //public static StepContext CreateContext(IServiceProvider di) + // where TResult:class + //{ + // Type strType = typeof(TResult);//获取泛型的结构 + // Type genericType = typeof(StepContext<>);//获取泛型上下文定义的结构 + // Type genericType2 = genericType.MakeGenericType(strType);//创建泛型上下文接口 + + // //获取实例 + // StepContext taskContext = di.GetService(genericType2) as StepContext; + + // //初始化结果数据 + // bool isNullResult = taskContext.Result.GetHashCode() == new object().GetHashCode(); + // if (isNullResult) + // { + // taskContext.ResultEntiy = di.GetService(); + // } + + // return taskContext; + //} + + ///// + ///// 创建一个新的. + ///// 里面的数据初始化部分不会负责 + ///// + ///// 上下文中返回的类型 + ///// + //public static StepContext CreateContext() + // where TResult : class + //{ + // StepContext tt = new StepContext + // { + // ResultEntiy = default + // }; + + // return tt; + //} + + /// + /// 创建一个新的. + /// + /// 上下文中结果的类型 + /// 要初始化到上下文中的结果 + /// + /// 表示初始化后的上下文是否已经完成任务。用来初始化属性 + /// + /// 初始化后的 + public static StepContext CreateContext( + TResult initObject, + bool completed = false) + where TResult : class + { + StepContext context = new StepContext(initObject, completed); + + return context; + } + + /// + /// 创建一个新的. + /// + /// + /// 表示初始化后的上下文是否已经完成任务。用来初始化属性 + /// + /// 初始化后的 + public static CkTools.Nova.Entity.StepContext CreateContext(bool completed = false) + { + return CkTools.Nova.Entity.StepContext.CreateContext(CkTools.Nova.Entity.StepContext.DefualtNullResult, completed); + } + + #endregion 创建StepContext + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Entity/StepContext.cs b/CkTools/Src/CkTools.Nova/Entity/StepContext.cs new file mode 100644 index 00000000..0026e5a1 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Entity/StepContext.cs @@ -0,0 +1,16 @@ +namespace CkTools.Nova.Entity +{ + /// + /// 执行逻辑链的上下文 + /// + public abstract partial class StepContext + { + /// + /// 是否分析完成 + /// + /// + /// 不建议手动设置此属性的值。 + /// + public virtual bool ProcessCompleted { get; set; } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs b/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs new file mode 100644 index 00000000..6a91957c --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs @@ -0,0 +1,28 @@ +namespace CkTools.Nova.Entity +{ + /// + /// 针对及其泛型的扩展方法 + /// + public static class StepContextExtension + { + #region 获取TaskContext + + /// + /// 获取泛型的上下文 + /// + /// + /// + /// + /// 转换逻辑同As关键字 + /// 因为使用不太方便,所以提供了此方法,代替了自己转换 + /// 能转换的前提是已经是类型的上下文了。 + /// + /// + public static StepContext As(this CkTools.Nova.Entity.StepContext taskContext) + { + return taskContext as StepContext; + } + + #endregion 获取TaskContext + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Entity/StepContextGeneric.cs b/CkTools/Src/CkTools.Nova/Entity/StepContextGeneric.cs new file mode 100644 index 00000000..44b3f8c2 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Entity/StepContextGeneric.cs @@ -0,0 +1,42 @@ +using CkTools.Nova.LogicChain; + +namespace CkTools.Nova.Entity +{ + /// + /// 执行逻辑链的泛型上下文 + /// + public class StepContext : StepContext + { + /// + /// 初始化一个实例 + /// + /// 初始化到上下文实例中的结果 + /// 初始化到上下文中的处理结果 + public StepContext(TResult result, bool completed) + { + this.Result = result; + base.ProcessCompleted = completed; + } + + /// + /// 初始化一个实例 + /// + /// 初始化到上下文实例中的结果 + public StepContext(TResult result) : this(result, false) + { + } + + /// + /// 初始化一个实例 + /// + public StepContext() : this(default, false) + { + } + + /// + /// 当前上下文中的返回数据 + /// + /// + public TResult Result { get; internal set; } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Entity/StepEntity.cs b/CkTools/Src/CkTools.Nova/Entity/StepEntity.cs new file mode 100644 index 00000000..3987e1a0 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Entity/StepEntity.cs @@ -0,0 +1,32 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.LogicChain; +using System; + +namespace CkTools.Nova.Entity +{ + /// + /// 注册、排序过程中使用的最小单位数据。 框架使用 + /// + /// + /// 在注册、排序过程中有很多上下文的关系,这里用一个类装起来。 + /// 每个都是代表单步操作的数据 + /// + public class StepEntity + { + /// + /// 逻辑链注册的特性 + /// + public StepAttribute Attribute { get; set; } + + /// + /// 实现类的数据。 + /// 只会是直接或间接继承接口或接口的类 + /// + public Type StepType { get; set; } + + /// + /// 步骤实例对象 + /// + public IStep StepInstanceObject { get; set; } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Factory/ILogicalChainFactory.cs b/CkTools/Src/CkTools.Nova/Factory/ILogicalChainFactory.cs new file mode 100644 index 00000000..63a21d06 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Factory/ILogicalChainFactory.cs @@ -0,0 +1,32 @@ +using CkTools.Nova.Entity; +using CkTools.Nova.LogicChain; +using System; +using System.Collections.Generic; + +namespace CkTools.Nova.Factory +{ + /// + /// 逻辑链工厂接口 + /// + public interface INovaFactory + { + /// + /// 按不同的步骤枚举类型,获取第一个可执行的步骤实现 + /// + /// + /// + IStep GetFirstTask(); + + /// + /// 获取所有的步骤枚举和对应的实现数据 + /// + /// 帮助整理的集合。默认返回工厂缓存的数据 + /// + /// 此方法提供给调试时使用,开发使用方法即可。 + /// 如果是启动时调用:会扫描程序集然后注册、添加、排序等等。 + /// 如果是启动后调用:会返回缓存中的数据。 + /// + /// + Dictionary GetNovaList(List? taskList = null); + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs b/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs new file mode 100644 index 00000000..d84f42a6 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs @@ -0,0 +1,183 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Entity; +using CkTools.Nova.Helper; +using CkTools.Nova.LogicChain; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; + +namespace CkTools.Nova.Factory +{ + /// + /// 接口的默认实现 + /// + public class NovaFactory : INovaFactory + { + /// + /// 放存步骤中间件的字典。 + /// key为步骤枚举的类型 + /// value为步骤枚举对应的步骤实现,已经排列好调用顺序,第一个既可执行 + /// + private readonly ConcurrentDictionary taskList; + + /// + /// DI实例 + /// + private readonly IServiceProvider di; + + /// + /// 初始化一个 实例 + /// + /// DI实例 + /// + /// 需要处理的 集合。可调用 获得 + /// + public NovaFactory(IServiceProvider serviceProvider, List taskList) + { + this.di = serviceProvider; + + var tempTaskList = this.GetNovaList(taskList); + this.taskList = new ConcurrentDictionary(tempTaskList); + } + + /// + /// 按获取第一个可执行的任务实例。 + /// + /// + /// + public IStep GetFirstTask() + { + StepEntity[] taskEntity = this.taskList.GetOrAdd( + typeof(TEnumType), + type => this.GetTaskEntity(type) + ); + + return taskEntity + .FirstOrDefault() + ?.StepInstanceObject; + } + + #region 获取、排列 + + /// + /// 获取所有的步骤枚举和对应的实现数据 + /// + /// 帮助整理的集合。默认返回工厂缓存的数据 + /// + /// 此方法提供给调试时使用,开发使用方法即可。 + /// 如果是启动时调用:会扫描程序集然后注册、添加、排序等等。 + /// 如果是启动后调用:会返回缓存中的数据。 + /// + /// + public Dictionary GetNovaList(List? taskList = null) + { + if (this.taskList.IsNullOrEmpty()) + { + //1.获取Type数据 + taskList ??= this.A_FindAllTaskEntity(); + + //2.创建或获取接口 + taskList = this.B_CreateInstance(taskList, this.di); + + //3.排序-排列接口上的Next + return this.C_SortAndPermutation(taskList); + } + else + { + return this.taskList.ToDictionary(t => t.Key, t => t.Value); + } + } + + /// + /// 整理、获取所有的Task + /// + /// + private StepEntity[] GetTaskEntity(Type enumType) + { + //1.获取Type数据 + List tempTaskList = this.A_FindAllTaskEntity(); + + //2.创建或获取接口 + this.B_CreateInstance(tempTaskList, this.di); + + //3.排序-排列接口上的Next + //分组-以type为索引 + var taskGroup = tempTaskList.FindAll(t => t.Attribute.StepEnumType == enumType); + + //排列next属性 + return LogicalChainHelper.SortList(taskGroup); + } + + /// + /// 找出所有程序集中所有包含的类数据 + /// + /// + private List A_FindAllTaskEntity() + { + return LogicalChainHelper.FindAllTaskEntity(); + } + + private List B_CreateInstance(in List taskList, IServiceProvider di) + { + foreach (var item in taskList) + { + item.StepInstanceObject = this.CreateInstance(item.StepType, di); + } + return taskList; + } + + /// + /// 排序后排列next调用 + /// + /// + /// + private Dictionary C_SortAndPermutation(in List taskList) + { + var taskGroup = taskList + .ToLookup(t => t.Attribute.StepEnumType); + + Dictionary result = new Dictionary(); + foreach (var item in taskGroup) + { + var temp = LogicalChainHelper.SortList(item.ToList()); + + result.Add(item.Key, temp); + } + + return result; + } + + #endregion 获取、排列 + + #region 创建实例 + + /// + ///(适合构造方法无参数) 利用框架自带的激活器创建实例. + /// + /// 要创建的类型 + /// DI实例 + /// + private TInstance CreateInstance(Type type, IServiceProvider di) + where TInstance : class + { + return di.GetService(type) as TInstance; + } + + /// + /// (适合构造方法有参数)利用框架自带的激活器创建实例. + /// + /// 要创建的类型 + /// 构造方法中要求的参数,按顺序传递 + /// + private TInstance CreateInstance(Type type, params object[] args) + where TInstance : class, new() + { + TInstance tempInstance = Activator.CreateInstance(type, args) as TInstance;//利用这个自带的激活器创建,也可以修改为DI实例 + + return tempInstance; + } + + #endregion 创建实例 + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs b/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs new file mode 100644 index 00000000..709601d9 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs @@ -0,0 +1,166 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Entity; +using CkTools.Nova.LogicChain; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace CkTools.Nova.Helper +{ + /// + /// 逻辑链帮助类 + /// + public static class LogicalChainHelper + { + #region 筛选 + + /// + /// 从载入的程序集中查找 + /// + /// + /// predicate参数示例: + /// + /// func = i =>{ return i.IsClass && i.IsPublic ; };]]> + /// + /// + /// 用来过滤type的委托 + /// + public static IList<(TAttribute attribute, Type Type)> GetCustomAttributesByAssemblies(Func predicate) + where TAttribute : Attribute + { + var types = AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(i => + { + try + { + return i.GetExportedTypes(); + } + catch + { + return new Type[0]; + } + }) + .Where(predicate) + .Select(type => (Attribute: type.GetCustomAttribute(false), type)) + .Where(attr => attr.Attribute != null) + .ToList() + ; + + //var types = AppDomain.CurrentDomain.GetAssemblies() + // .SelectMany(i => + // { + // try + // { + // return i.GetExportedTypes(); + // } + // catch + // { + // return new Type[0]; + // } + // }) + // .Where(predicate) + // .SelectMany(type => type + // .GetCustomAttributes() + // .Select(attr => (attr, type) + // ) + + // ); + + return types; + } + + /// + /// 找出所有程序集中所有包含的类数据 + /// + /// + public static List FindAllTaskEntity() + { + Func func = i => + { + return i.IsClass //类 + && i.IsEnum //枚举 + && i.IsPublic //公共的 + //&& i.IsGenericType == false //泛型类型 + // && i.IsGenericTypeDefinition == false//泛型具体实现 + // && i.IsAbstract == false //抽象 + + ; + }; + + List taskStructList = LogicalChainHelper + .GetCustomAttributesByAssemblies(func) + .Select(t => new StepEntity() { StepType = t.Type, Attribute = t.attribute }) + .ToList(); + return taskStructList; + } + + #endregion 筛选 + + #region 排列接口 + + /// + /// 按输入的排列。返回第一个可执行的 + /// 适合:已经确定好所有的步骤,仅仅只是排列调用顺序 + /// + /// 需要排序的迭代器 + /// + /// 是否自动添加结尾的中间件,用来标记执行结束.因为排序时有可能是自动排序,有可能是手动排序,所以此方法不能确定最后一个的情况。 + /// 传递false时会自动附加一个空的以防止空指针异常 + /// + /// 排好顺序后,第一个可执行的 + public static IStep Sort( + IEnumerable taskArray, + bool isAutoEnd = true) + { + return LogicalChainHelper.SortList(taskArray, isAutoEnd)[0].StepInstanceObject; + } + + /// + /// 按输入的排列。 + /// 适合:已经确定好所有的步骤,仅仅只是排列调用顺序 + /// + /// 需要排序的迭代器 + /// + /// 是否自动添加结尾的中间件,用来标记执行结束.因为排序时有可能是自动排序,有可能是手动排序,所以此方法不能确定最后一个的情况。 + /// 传递false时会自动附加一个空的以防止空指针异常 + /// + /// 排列好顺序和next调用的数组 + public static StepEntity[] SortList( + IEnumerable taskArray, + bool isAutoEnd = true) + { + //排序 一组接口内部排序 + var stepList = taskArray + .OrderBy(i => i.Attribute.StepEnumOrder) + .ToArray(); + + StepEntity tempMw = stepList.First();//获取第一个中间件的引用 + foreach (var item in stepList) + { + tempMw.StepInstanceObject.Next = item.StepInstanceObject; + tempMw = item;//将指针移动到下一个 + } + + //处理最后一个中间件的next。 分析完成后tempMw指向最后一个中间件 + tempMw.StepInstanceObject.Next = isAutoEnd + ? LogicalChainHelper.GetEndStep() + : null; + + return stepList; + } + + #endregion 排列接口 + + #region 创建默认的EndStep + + public static readonly IStep DefaultEndStep = new EndStep(); + + public static IStep GetEndStep() + { + return LogicalChainHelper.DefaultEndStep; + } + + #endregion 创建默认的EndStep + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/LogicChain/EndStep.cs b/CkTools/Src/CkTools.Nova/LogicChain/EndStep.cs new file mode 100644 index 00000000..47d4f31e --- /dev/null +++ b/CkTools/Src/CkTools.Nova/LogicChain/EndStep.cs @@ -0,0 +1,15 @@ +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.LogicChain +{ + /// + /// 结束调用链,代表最后一步 + /// + public class EndStep : StepBase + { + protected override void ProcessContext(StepContext context) + { + base.Complete(); + } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/LogicChain/EndStepGeneric.cs b/CkTools/Src/CkTools.Nova/LogicChain/EndStepGeneric.cs new file mode 100644 index 00000000..9efb9598 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/LogicChain/EndStepGeneric.cs @@ -0,0 +1,16 @@ +using CkTools.Nova.Entity; + +namespace CkTools.Nova.LogicChain +{ + /// + /// 结束调用链,代表最后一步。 + /// + /// + public class EndStep : StepBase + { + protected override void ProcessContext(StepContext context) + { + base.Complete(); + } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs b/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs new file mode 100644 index 00000000..61106405 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs @@ -0,0 +1,31 @@ +using CkTools.Nova.Helper; +using System.Threading.Tasks; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.LogicChain +{ + /// + /// 任务步骤接口,一个实现对应一步逻辑 + /// + public interface IStep + { + /// + /// 下一个中间件 + /// + /// + /// 由中排序或初始化时统一指定 + /// + IStep Next { get; set; } + + /// + /// 异步执行任务 + /// + /// 要处理的步骤上下文. + /// + /// 参数初始化: + /// 一般来说第一个步骤代码执行时不会判断null,由调用者负责初始化化。如果使用IOC,则不需要关心此参数 + /// + /// + Task InvokeAsync(StepContext context); + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/LogicChain/IStepGeneric.cs b/CkTools/Src/CkTools.Nova/LogicChain/IStepGeneric.cs new file mode 100644 index 00000000..4db4956c --- /dev/null +++ b/CkTools/Src/CkTools.Nova/LogicChain/IStepGeneric.cs @@ -0,0 +1,23 @@ +using CkTools.Nova.Entity; +using System.Threading.Tasks; + +namespace CkTools.Nova.LogicChain +{ + /// + /// 泛型任务步骤接口,一个实现对应一步逻辑 + /// + /// 步骤处理的结果类型 + public interface IStep : IStep + { + /// + /// 异步执行任务 + /// + /// 要处理的步骤上下文. + /// + /// 参数初始化: + /// 一般来说第一个步骤代码执行时不会判断null,由调用者负责初始化化。如果使用IOC,则不需要关心此参数 + /// + /// + Task InvokeAsync(StepContext context); + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs b/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs new file mode 100644 index 00000000..ab28c5ee --- /dev/null +++ b/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs @@ -0,0 +1,44 @@ +using System; +using System.Threading.Tasks; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.LogicChain +{ + public abstract class StepBase : IStep + { + public IStep Next { get; set; } + + public StepContext Context { get; set; } + + public Task InvokeAsync(StepContext context) + { + context.CheckNullWithException(nameof(context)); + this.Context = context; + + //检查任务是否完成 + if (this.Context.ProcessCompleted || this.Next == null) + { + return Task.CompletedTask; + } + + //执行任务 + this.ProcessContext(context); + + //调用下一个任务 + return this.Next.InvokeAsync(context); + } + + /// + /// 由子类实现每个步骤的具体逻辑 + /// + /// + /// + protected abstract void ProcessContext(StepContext context); + + protected virtual StepContext Complete() + { + this.Context.ProcessCompleted = true; + return this.Context; + } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs b/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs new file mode 100644 index 00000000..7d1345b9 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs @@ -0,0 +1,44 @@ +using CkTools.Nova.Entity; +using System.Threading.Tasks; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.LogicChain +{ + public abstract class StepBase : StepBase, IStep + { + public new IStep Next { get; set; } + public new StepContext Context { get; set; } + + public Task InvokeAsync(StepContext context) + { + base.InvokeAsync(context); + + return Task.FromResult(this.Context.As().Result); + } + + /// + /// 由子类实现每个步骤的具体逻辑 + /// + /// + /// + protected abstract void ProcessContext(StepContext context); + + protected override void ProcessContext(StepContext context) + { + this.ProcessContext(context.As()); + } + + /// + /// 给属性赋值为true,结束当前的步骤链 + /// + /// + /// + protected virtual StepContext Complete(TResult result) + { + base.Complete(); + + this.Context.Result = result; + return this.Context.As(); + } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Middleware/LogicChainExtension.cs b/CkTools/Src/CkTools.Nova/Middleware/LogicChainExtension.cs new file mode 100644 index 00000000..3f84216d --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Middleware/LogicChainExtension.cs @@ -0,0 +1,42 @@ +using CkTools.Nova.Entity; +using CkTools.Nova.Factory; +using CkTools.Nova.Helper; +using System; +using System.Collections.Generic; + +namespace Microsoft.Extensions.DependencyInjection +{ + /// + /// 逻辑链扩展 + /// + public static class LogicChainExtension + { + /// + /// 注册逻辑链服务 + /// + /// + /// + public static IServiceCollection AddNova(this IServiceCollection services) + { + //扫描并注册程序集中所有带标签的实现 + List taskList = LogicalChainHelper.FindAllTaskEntity(); + foreach (var item in taskList) + { + ServiceDescriptor serviceDescriptor = new ServiceDescriptor( + item.StepType, + item.StepType, + item.Attribute.Lifetime); + + services.Add(serviceDescriptor); + } + + //注册工厂接口 + services.AddSingleton(t => + { + return new NovaFactory(t.GetService(), taskList); + }); + + return services; + } + } +} \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Middleware/TaskMwHelper.cs b/CkTools/Src/CkTools.Nova/Middleware/TaskMwHelper.cs new file mode 100644 index 00000000..87ed1614 --- /dev/null +++ b/CkTools/Src/CkTools.Nova/Middleware/TaskMwHelper.cs @@ -0,0 +1,35 @@ +//using System.Linq; + +//namespace Nova.LogicChain +//{ +// /// +// /// 还没想好名字的帮助类 +// /// +// public class TaskHelper +// { +// /// +// /// 按输入顺序排列每个ITaskMw中的下一个中间件,会自动设置执行顺序。 +// /// +// /// +// /// +// /// 排好顺序后,第一个执行的中间件 +// /// +// /// +// /// 关于最后一个中间件: +// /// 这种方式 +// /// +// /// 但是因执行限制,请自行控制最后一个中间件的Next属性,避免运行时造成空指针异常 +// /// +// public ITask SortByUse(params ITask[] taskList) +// { +// ITask tempMw = taskList.FirstOrDefault(); +// foreach (var item in taskList) +// { +// tempMw.Next = item; +// tempMw = item;//将指针移动到下一个 +// } + +// return taskList[0]; +// } +// } +//} \ No newline at end of file diff --git a/CkTools/Src/SDKPulishNuget.targets b/CkTools/Src/SDKPulishNuget.targets index b572687c..643379fe 100644 --- a/CkTools/Src/SDKPulishNuget.targets +++ b/CkTools/Src/SDKPulishNuget.targets @@ -15,7 +15,7 @@ $(VersionSuffix) - 3.1.0.7 + 3.1.0.8 $(Version)$(VersionSuffix) $(Version) $(Version) diff --git a/CkTools/Test/CKTols.FP.Test/Maybe`1Test.cs b/CkTools/Test/CKTols.FP.Test/Maybe`1Test.cs index d601f474..b5fb9b0b 100644 --- a/CkTools/Test/CKTols.FP.Test/Maybe`1Test.cs +++ b/CkTools/Test/CKTols.FP.Test/Maybe`1Test.cs @@ -5,6 +5,9 @@ namespace CKTols.FP.Test { public class Maybe_1Test { +#pragma warning disable CS8600 // 将 null 文本或可能的 null 值转换为不可为 null 类型。 +#pragma warning disable CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 + public class ConstructorTest { [Fact] @@ -68,6 +71,9 @@ public void MaybeParameterIsHasValueIsFalse_WithHasValueIsFalse() } } +#pragma warning restore CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 +#pragma warning restore CS8600 // 将 null 文本或可能的 null 值转换为不可为 null 类型。 + public class ImplicitOperatorTest { [Fact] diff --git a/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/BaseType/IEnumerableExtensionsTest.cs b/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/BaseType/IEnumerableExtensionsTest.cs index 3d292af0..410dc481 100644 --- a/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/BaseType/IEnumerableExtensionsTest.cs +++ b/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/BaseType/IEnumerableExtensionsTest.cs @@ -197,7 +197,7 @@ public class IntersectTest [Fact] public void Source_Null() { - List testData = null; + List? testData = null; Func func = (a, b) => a.UserName == b.UserName; var ex = Assert.Throws(() => diff --git a/CkTools/Test/CkTools.Abstraction.Test/Extensions/EnumerableExtensions.cs b/CkTools/Test/CkTools.Abstraction.Test/Extensions/EnumerableExtensions.cs new file mode 100644 index 00000000..087f0795 --- /dev/null +++ b/CkTools/Test/CkTools.Abstraction.Test/Extensions/EnumerableExtensions.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections; +using Xunit; + +namespace Nova.LogicChain.Test.Extensions +{ + public class EnumerableExtensions + { + #region IsNullOrEmpty + + [Fact] + public void IsNullOrEmpty_Null_True() + { + IEnumerable testObject = null; + bool result = testObject.IsNullOrEmpty(); + Assert.True(result); + } + + [Fact] + public void IsNullOrEmpty_Empty_True() + { + IEnumerable testObject = new int[0]; + bool result = testObject.IsNullOrEmpty(); + Assert.True(result); + } + + [Fact] + public void IsNullOrEmpty_ZeroIsNull_Fasle() + { + IEnumerable testObject = new string[2] { null, null }; + bool result = testObject.IsNullOrEmpty(); + Assert.False(result); + } + + [Fact] + public void IsNullOrEmpty_TwoElement_Fasle() + { + IEnumerable testObject = new string[2] { "1", "1" }; + bool result = testObject.IsNullOrEmpty(); + Assert.False(result); + } + + #endregion IsNullOrEmpty + + #region IsNotNullOrEmpty + + [Fact] + public void IsNotNullOrEmpty_Null_Fasle() + { + IEnumerable testObject = null; + bool result = testObject.IsNotNullOrEmpty(); + Assert.False(result); + } + + [Fact] + public void IsNotNullOrEmpty_Empty_Fasle() + { + IEnumerable testObject = new int[0]; + bool result = testObject.IsNotNullOrEmpty(); + Assert.False(result); + } + + [Fact] + public void IsNotNullOrEmpty_ZeroIsNull_True() + { + IEnumerable testObject = new string[2] { null, null }; + bool result = testObject.IsNotNullOrEmpty(); + Assert.True(result); + } + + [Fact] + public void IsNotNullOrEmpty_TwoElement_True() + { + IEnumerable testObject = new string[2] { "1", "1" }; + bool result = testObject.IsNotNullOrEmpty(); + Assert.True(result); + } + + #endregion IsNotNullOrEmpty + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Abstraction.Test/Extensions/ObjectExtensionsTest.cs b/CkTools/Test/CkTools.Abstraction.Test/Extensions/ObjectExtensionsTest.cs new file mode 100644 index 00000000..c2d4cec8 --- /dev/null +++ b/CkTools/Test/CkTools.Abstraction.Test/Extensions/ObjectExtensionsTest.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Xunit; + +namespace Nova.LogicChain.Test.Extensions +{ + public class ObjectExtensionsTest + { + #region CheckNull + + [Fact] + public void CheckNull_True() + { + object obj = null; + var ex = Assert.Throws(() => obj.CheckNullWithException("test")); + + Assert.NotNull(ex); + } + + [Fact] + public void CheckNull_False() + { + object obj = new object(); + var ex = Record.Exception(() => obj.CheckNullWithException("test")); + + Assert.Null(ex); + } + + [Fact] + public void CheckNull2_True() + { + object obj = null; + var ex = Assert.Throws(() => obj.CheckNullWithException("test", "testMsg")); + + Assert.NotNull(ex); + Assert.Contains("testMsg", ex.Message); + } + + [Fact] + public void CheckNull2_False() + { + object obj = new object(); + var ex = Record.Exception(() => obj.CheckNullWithException("test", "testMsg")); + + Assert.Null(ex); + } + + #endregion CheckNull + + #region CheckNullOrEmpty + + [Fact] + public void CheckNullOrEmpty_Null_True() + { + List obj = null; + var ex = Assert.Throws(() => obj.CheckNullOrEmptyWithException("test")); + + Assert.NotNull(ex); + } + + [Fact] + public void CheckNullOrEmpty_Empty_True() + { + List obj = new List(); + var ex = Assert.Throws(() => obj.CheckNullOrEmptyWithException("test")); + + Assert.NotNull(ex); + } + + [Fact] + public void CheckNullOrEmpty_False() + { + List obj = new List() { 1 }; + var ex = Record.Exception(() => obj.CheckNullOrEmptyWithException("test")); + + Assert.Null(ex); + } + + [Fact] + public void CheckNullOrEmpty2_Null_True() + { + List obj = null; + var ex = Assert.Throws(() => obj.CheckNullOrEmptyWithException("test", "testMsg")); + + Assert.NotNull(ex); + Assert.Contains("testMsg", ex.Message); + } + + [Fact] + public void CheckNullOrEmpty2_Empty_True() + { + List obj = new List(); + var ex = Assert.Throws(() => obj.CheckNullOrEmptyWithException("test", "testMsg")); + + Assert.NotNull(ex); + Assert.Contains("testMsg", ex.Message); + } + + [Fact] + public void CheckNullOrEmpty2_False() + { + List obj = new List() { 1 }; + var ex = Record.Exception(() => obj.CheckNullOrEmptyWithException("test", "testMsg")); + + Assert.Null(ex); + } + + #endregion CheckNullOrEmpty + + #region ToTask + + [Fact] + public void ToTask_NullObject_NotException() + { + object obj = null; + Task result = null; + var ex = Record.Exception(() => { result = obj.ToTask(); }); + + Assert.Null(ex); + Assert.True(result.IsCompleted); + Assert.Null(result.Result); + } + + [Fact] + public void ToTask_String_NotException() + { + string obj = "123"; + Task result = null; + var ex = Record.Exception(() => { result = obj.ToTask(); }); + + Assert.Null(ex); + Assert.True(result.IsCompleted); + Assert.Equal(obj, result.Result); + } + + #endregion ToTask + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs b/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs new file mode 100644 index 00000000..f8bb8b02 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs @@ -0,0 +1,85 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Test.TestModel; +using Microsoft.Extensions.DependencyInjection; +using Nova.LogicalChain.Test; +using System; +using Xunit; + +namespace CkTools.Nova.Test.Aop +{ + public class LogicChainStepAttributeTest + { + #region Construction method + + [Fact] + public void Construction_One_Parameter() + { + var result = new StepAttribute(TestTaskEnum.Start); + + Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); + Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); + Assert.Null(result.ContextResultType); + Assert.Equal(ServiceLifetime.Singleton, result.Lifetime); + } + + [Fact] + public void Construction_Two_Parameter() + { + var result = new StepAttribute(TestTaskEnum.Start, ServiceLifetime.Scoped); + + Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); + Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); + Assert.Null(result.ContextResultType); + Assert.Equal(ServiceLifetime.Scoped, result.Lifetime); + } + + [Fact] + public void Construction_Two_Parameter2() + { + var result = new StepAttribute(TestTaskEnum.Start, typeof(TestResult)); + + Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); + Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); + Assert.NotNull(result.ContextResultType); + Assert.Equal(typeof(TestResult), result.ContextResultType); + Assert.Equal(ServiceLifetime.Singleton, result.Lifetime); + } + + [Fact] + public void Construction_Three_Parameter() + { + var result = new StepAttribute(TestTaskEnum.Start, typeof(TestResult), ServiceLifetime.Transient); + + Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); + Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); + Assert.NotNull(result.ContextResultType); + Assert.Equal(typeof(TestResult), result.ContextResultType); + Assert.Equal(ServiceLifetime.Transient, result.Lifetime); + } + + [Fact] + public void Construction_stepEnumTypeValue_Null() + { + var ex = Assert.Throws(() => + { +#pragma warning disable CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 + _ = new StepAttribute(null, typeof(TestResult)); +#pragma warning restore CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 + }); + + Assert.Null(ex); + } + + [Fact] + public void Construction_stepEnumTypeValue_NoEnum() + { + var ex = Assert.Throws(() => + { + _ = new StepAttribute(123, typeof(TestResult)); + }); + Assert.Null(ex); + } + + #endregion Construction method + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/CkTools.Nova.Test.csproj b/CkTools/Test/CkTools.Nova.Test/CkTools.Nova.Test.csproj new file mode 100644 index 00000000..c6e2da26 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/CkTools.Nova.Test.csproj @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/DI_Test/DI_Test.cs b/CkTools/Test/CkTools.Nova.Test/DI_Test/DI_Test.cs new file mode 100644 index 00000000..91bb1568 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/DI_Test/DI_Test.cs @@ -0,0 +1,105 @@ +using CkTools.Nova.Entity; +using CkTools.Nova.Factory; +using CkTools.Nova.LogicChain; +using CkTools.Nova.Test.TestModel; +using Microsoft.Extensions.DependencyInjection; +using Nova.LogicalChain.Test; +using System; +using Xunit; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.Test.DI_Test +{ + public class DI_Test + { + [Fact] + public void Test_DI_StepA() + { + var mockObject = MockHelper.GetMockeTaskAndContext(100); + + //执行 + mockObject.ITask.InvokeAsync(mockObject.TestContext); + + //验证 + var result = mockObject.TestContext; + var resultObj = mockObject.TestContext.Result; + + Assert.True(result.ProcessCompleted); + Assert.Equal(100, resultObj.ID); + Assert.Contains("只执行到第一步", resultObj.Message); + } + + [Fact] + public void Test_DI_StepB() + { + var mockObject = MockHelper.GetMockeTaskAndContext(200); + + //执行 + mockObject.ITask.InvokeAsync(mockObject.TestContext); + + //验证 + var result = mockObject.TestContext; + var resultObj = mockObject.TestContext.Result; + + Assert.True(result.ProcessCompleted); + Assert.Equal(200, resultObj.ID); + Assert.Contains("只执行到第二步", resultObj.Message); + } + + [Fact] + public void Test_DI_StepC() + { + var mockObject = MockHelper.GetMockeTaskAndContext(300); + + //执行 + mockObject.ITask.InvokeAsync(mockObject.TestContext); + + //验证 + var result = mockObject.TestContext; + var resultObj = mockObject.TestContext.Result; + + Assert.True(result.ProcessCompleted); + Assert.Equal(300, resultObj.ID); + Assert.Contains(MockHelper.TestServiceName, resultObj.Message);//C这一步返回的是模拟配置中的数据 + } + + private static class MockHelper + { + public const string TestServiceName = "TestService"; + + public static IServiceProvider GetMockeDI() + { + IServiceCollection diBuilder = new ServiceCollection(); + diBuilder.AddNova();//注册服务 + + diBuilder.AddSingleton(new TestConfig() + { + ServiceName = MockHelper.TestServiceName, + IsRelease = true + } + ); + + IServiceProvider di = diBuilder.BuildServiceProvider(); + + return di; + } + + public static (IStep ITask, StepContext TestContext) GetMockeTaskAndContext(int expectID) + { + IServiceProvider di = MockHelper.GetMockeDI(); + + IStep testTask = di + .GetService() + .GetFirstTask(); + + TestResult testContext = new TestResult() + { + ID = expectID, + }; + StepContext taskContext = StepContext.CreateContext(testContext); + + return (testTask, taskContext); + } + } + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/Factory/LogicalChainFactoryTest.cs b/CkTools/Test/CkTools.Nova.Test/Factory/LogicalChainFactoryTest.cs new file mode 100644 index 00000000..01df0447 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/Factory/LogicalChainFactoryTest.cs @@ -0,0 +1,12 @@ +using Xunit; + +namespace CkTools.Nova.Test.Factory +{ + public class LogicalChainFactoryTest + { + [Fact] + public void GetNovaList_Null() + { + } + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/LogicChain/LogicalChainHelperTest.cs b/CkTools/Test/CkTools.Nova.Test/LogicChain/LogicalChainHelperTest.cs new file mode 100644 index 00000000..35b7b7d9 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/LogicChain/LogicalChainHelperTest.cs @@ -0,0 +1,234 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Entity; +using CkTools.Nova.Helper; +using CkTools.Nova.LogicChain; +using CkTools.Nova.Test.TestModel; +using Nova.LogicalChain.Test; +using System; +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace CkTools.Nova.Test.LogicChain +{ + public class LogicalChainHelperTest + { + [Fact] + public void FindAllTaskEntity_True() + { + } + + private static class MockHeler + { + //这里为了测试 枚举与步骤都是倒着来的 + + public static readonly Dictionary stepTypeDic = new Dictionary() + { + {1,typeof(Test_C_Step) }, + {2,typeof(Test_B_Step) }, + {3,typeof(Test_A_Step) } + }; + + public static StepEntity[] GetTestArray() + { + return new StepEntity[] + { + new StepEntity () + { + Attribute=new StepAttribute(TestTaskEnum.EndLog,typeof(TestResult)), + StepInstanceObject=new Test_A_Step() + }, + new StepEntity () + { + Attribute=new StepAttribute(TestTaskEnum.End,typeof(TestResult)), + StepInstanceObject=new Test_B_Step() + }, + new StepEntity () + { + Attribute=new StepAttribute(TestTaskEnum.Start,typeof(TestResult)), + StepInstanceObject=new Test_C_Step(new TestConfig()) + } + }; + } + + public static bool CheckCallChain(StepEntity[] stepEntity, bool isAutoEnd) + { + /* + * 检查目标: + * 1.Order是不是递增 + * 2.如果 isAutoEnd 为True,则需要最后一步的Next属性的情况 + * isAutoEnd 为True时,数组中最后一步的Next不能为null,并且类型应该给为EndStep + * + */ + + int initOrder = int.MinValue; + bool result = true; //都是&& 有一个false都是false + + foreach (var item in stepEntity) + { + result = result && item.Attribute.StepEnumOrder >= initOrder;//检查点 + + bool isEndStep = item.GetType() == MockHeler.stepTypeDic.Last().Value;//判断是否为最后一个步骤 + if (isEndStep && isAutoEnd) + { + result = result && item.StepInstanceObject.Next != null;//检查点 + result = result && item.StepInstanceObject.Next.GetType() == typeof(EndStep);//检查点 + } + + initOrder = item.Attribute.StepEnumOrder; + } + + return result; + } + + public static bool CheckCallChain(IStep step, bool isAutoEnd = true, int typeOrder = 1, bool? middleResult = null) + { + /* + * 检查目标: + * 1.Next是不是有值 + * 2.类型对不对,应该按 MockHeler.stepTypeDic 中的类型来 + * 3.如果 isAutoEnd 为True,则需要最后一步的Next属性的情况 + * isAutoEnd 为True时,数组中最后一步的Next不能为null,并且类型应该给为EndStep + * + */ + + bool result = middleResult ?? true; //都是&& 有一个false都是false + + bool isEndStep = typeOrder == MockHeler.stepTypeDic.Last().Key;//判断是否为最后一个步骤 + bool isExists = MockHeler.stepTypeDic.TryGetValue(typeOrder, out Type stepType); + + if (!isExists)//不存在的key,需要退出递归 + { + return result; + } + + if (isEndStep && isAutoEnd)//最后一步 但 isAutoEnd 为true时 要检查Next的状态 + { + result = result && step.Next != null;//检查点3 + result = result && step.Next.GetType() == typeof(EndStep);//检查点3 + + return result; + } + else if (isEndStep && !isAutoEnd) + { + //最后一步 但 isAutoEnd 为false时 不检查Next的状态 + result = result && step.GetType() == stepType;//检查点2 + return result; + } + else//常规检查 + { + result = result && step.Next != null;//检查点1 + result = result && step.GetType() == stepType;//检查点2 + return CheckCallChain(step.Next, isAutoEnd, typeOrder + 1, result); + } + } + } + + #region Sort + + [Fact] + public void Sort_SortIsTrue_AutoEnd() + { + IStep result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.Sort(MockHeler.GetTestArray()); + }); + Assert.Null(ex); + + Assert.NotNull(result); + Assert.True(MockHeler.CheckCallChain(result)); + } + + [Fact] + public void Sort_SortIsTrue_NoAutoEnd() + { + IStep result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.Sort(MockHeler.GetTestArray(), false); + }); + + Assert.Null(ex); + Assert.NotNull(result); + Assert.True(MockHeler.CheckCallChain(result, false)); + } + + [Fact] + public void SortList_SortIsTrue_AutoEnd() + { + StepEntity[] result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.SortList(MockHeler.GetTestArray(), true); + }); + + Assert.Null(ex); + Assert.NotNull(result); + Assert.NotEmpty(result); + + Assert.True(MockHeler.CheckCallChain(result, true)); + } + + [Fact] + public void SortList_SortIsTrue_NoAutoEnd() + { + StepEntity[]? result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.SortList(MockHeler.GetTestArray(), false); + }); + + Assert.Null(ex); + Assert.NotNull(result); + Assert.NotEmpty(result); + + Assert.True(MockHeler.CheckCallChain(result, false)); + } + + [Fact] + public void SortList_AutoEnd() + { + StepEntity[] result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.SortList(MockHeler.GetTestArray()); + }); + + Assert.Null(ex); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.NotNull(result.Last().StepInstanceObject.Next); + } + + [Fact] + public void SortList_NoAutoEnd() + { + StepEntity[] result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.SortList(MockHeler.GetTestArray(), false); + }); + + Assert.Null(ex); + Assert.NotNull(result); + Assert.NotEmpty(result); + Assert.Null(result.Last().StepInstanceObject.Next); + } + + [Fact] + public void Sort_NoException() + { + IStep result = null; + var ex = Record.Exception(() => + { + result = LogicalChainHelper.Sort(MockHeler.GetTestArray()); + }); + + Assert.Null(ex); + Assert.NotNull(result); + } + + #endregion Sort + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/TestModel/TestConfig.cs b/CkTools/Test/CkTools.Nova.Test/TestModel/TestConfig.cs new file mode 100644 index 00000000..465f4829 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/TestModel/TestConfig.cs @@ -0,0 +1,12 @@ +namespace CkTools.Nova.Test.TestModel +{ + /// + /// 模拟实现需要从外部获取的配置类 + /// + public class TestConfig + { + public bool IsRelease { get; set; } + + public string? ServiceName { get; set; } + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/TestModel/TestResult.cs b/CkTools/Test/CkTools.Nova.Test/TestModel/TestResult.cs new file mode 100644 index 00000000..e1a9aaa1 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/TestModel/TestResult.cs @@ -0,0 +1,8 @@ +namespace Nova.LogicalChain.Test +{ + public class TestResult + { + public int ID { get; set; } + public string Message { get; set; } + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/TestModel/TestTaskEnum.cs b/CkTools/Test/CkTools.Nova.Test/TestModel/TestTaskEnum.cs new file mode 100644 index 00000000..0e308760 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/TestModel/TestTaskEnum.cs @@ -0,0 +1,16 @@ +namespace CkTools.Nova.Test.TestModel +{ +#pragma warning disable S2344 + + /// + /// 步骤枚举 + /// + public enum TestTaskEnum +#pragma warning restore S2344 + { + Start = 1, + End = 50, + + EndLog = 100 + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/TestModel/Test_A_Step.cs b/CkTools/Test/CkTools.Nova.Test/TestModel/Test_A_Step.cs new file mode 100644 index 00000000..b4a05bfa --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/TestModel/Test_A_Step.cs @@ -0,0 +1,36 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Entity; +using CkTools.Nova.LogicChain; +using Nova.LogicalChain.Test; +using System.Threading.Tasks; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.Test.TestModel +{ + [Step(TestTaskEnum.Start, typeof(TestResult))] + public class Test_A_Step : IStep + { + public IStep Next { get; set; } + + public Task InvokeAsync(StepContext context) + { + var conText2 = context.As(); + + // 模拟自己的操作 + + if (conText2.Result.ID == 100) + { + //模拟分支 + conText2.Result.Message = "只执行到第一步"; + context.ProcessCompleted = true; + return Task.CompletedTask; + } + + var endTask = this.Next.InvokeAsync(conText2); + + // 模拟上一步完成后自己的操作 + + return endTask; + } + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/TestModel/Test_B_Step.cs b/CkTools/Test/CkTools.Nova.Test/TestModel/Test_B_Step.cs new file mode 100644 index 00000000..a3810a92 --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/TestModel/Test_B_Step.cs @@ -0,0 +1,33 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Entity; +using CkTools.Nova.LogicChain; +using Nova.LogicalChain.Test; +using System.Threading.Tasks; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.Test.TestModel +{ + [Step(TestTaskEnum.End, typeof(TestResult))] + public class Test_B_Step : IStep + { + public IStep Next { get; set; } + + public Task InvokeAsync(StepContext context) + { + var conText2 = context.As(); + + if (conText2.Result.ID == 200) + { + //模拟分支 + conText2.Result.ID = 200; + conText2.Result.Message = "只执行到第二步"; + context.ProcessCompleted = true; + return Task.CompletedTask; + } + + var endTask = this.Next.InvokeAsync(conText2); + + return endTask; + } + } +} \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/TestModel/Test_C_Step.cs b/CkTools/Test/CkTools.Nova.Test/TestModel/Test_C_Step.cs new file mode 100644 index 00000000..adbe2acf --- /dev/null +++ b/CkTools/Test/CkTools.Nova.Test/TestModel/Test_C_Step.cs @@ -0,0 +1,42 @@ +using CkTools.Nova.Aop; +using CkTools.Nova.Entity; +using CkTools.Nova.LogicChain; +using Nova.LogicalChain.Test; +using System.Threading.Tasks; +using StepContext = CkTools.Nova.Entity.StepContext; + +namespace CkTools.Nova.Test.TestModel +{ + [Step(TestTaskEnum.EndLog, ContextResultType = typeof(TestResult))] + public class Test_C_Step : IStep + { + private readonly TestConfig testConfig; + + public Test_C_Step(TestConfig testConfig) + { + this.testConfig = testConfig; + } + + public IStep Next { get; set; } + + public Task InvokeAsync(StepContext context) + { + var t = new StepAttribute(TestTaskEnum.Start, typeof(StepContext)); + + var conText2 = context.As(); + + if (this.testConfig.IsRelease) + { + //模拟分支 + conText2.Result.ID = 300; + conText2.Result.Message = $"ServiceName:{this.testConfig.ServiceName}"; + context.ProcessCompleted = true; + return Task.CompletedTask; + } + else + { + return Task.CompletedTask; + } + } + } +} \ No newline at end of file From 7eecb9995af3bf28ecdc9ed57992a17657d93471 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Mon, 14 Sep 2020 10:24:08 +0800 Subject: [PATCH 02/15] =?UTF-8?q?=E5=A2=9E=E5=8A=A0pipe=E7=9A=84bool?= =?UTF-8?q?=E5=80=BC=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FpExtensions/FpObjectPipeExtensions.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CkTools/Src/CkTools.FP/Extensions/FpExtensions/FpObjectPipeExtensions.cs b/CkTools/Src/CkTools.FP/Extensions/FpExtensions/FpObjectPipeExtensions.cs index 585fbaab..98d1fa7e 100644 --- a/CkTools/Src/CkTools.FP/Extensions/FpExtensions/FpObjectPipeExtensions.cs +++ b/CkTools/Src/CkTools.FP/Extensions/FpExtensions/FpObjectPipeExtensions.cs @@ -35,6 +35,26 @@ [NotNull] Func func } } + /// + /// 管道 + /// a->(()->bool)->(b->c) => c + /// 示例: string->(string->bool)->(string->int) => int + /// + /// + /// :要处理的值 + /// :判断是否执行,返回true为执行 + /// :将要执行的处理 + /// + /// 可传递任意类型 + /// + public static TInput Pipe( + this TInput input, + bool isExecute, + Func func) + { + return input.Pipe(t => isExecute, func); + } + /// /// 管道 /// a->(a->b) => b From 68a2c27b68ccf5be312ad6316c79ddc41a151d14 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Mon, 14 Sep 2020 11:19:25 +0800 Subject: [PATCH 03/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=A1=A8=E8=BE=BE?= =?UTF-8?q?=E5=BC=8F=E5=B8=AE=E5=8A=A9=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Helper/ExpressionHelper.cs | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 CkTools/Src/CkTools.BaseExtensions/Helper/ExpressionHelper.cs diff --git a/CkTools/Src/CkTools.BaseExtensions/Helper/ExpressionHelper.cs b/CkTools/Src/CkTools.BaseExtensions/Helper/ExpressionHelper.cs new file mode 100644 index 00000000..b73fa843 --- /dev/null +++ b/CkTools/Src/CkTools.BaseExtensions/Helper/ExpressionHelper.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; + +namespace CkTools.Helper +{ + /// + /// 表达式帮助类 + /// + public static class ExpressionHelper + { + /// + /// 创建一个访问属性的表达式 + /// + /// 表达式 + /// 属性名称 + /// + public static Expression Property(this Expression expression, string propertyName) + { + return Expression.Property(expression, propertyName); + } + + /// + /// 条件表达式且(第一个true才执行第二个) + /// + /// 左表达式 + /// 右表达式 + /// + public static Expression AndAlso(this Expression left, Expression right) + { + return Expression.AndAlso(left, right); + } + + /// + /// 创建一个回调带有参数方法的表达式 + /// + /// 表达式 + /// 方法名字 + /// 参数 + /// + public static Expression Call(this Expression instance, string methodName, params Expression[] arguments) + { + return Expression.Call(instance, instance.Type.GetMethod(methodName), arguments); + } + + /// + /// 创建一个比较表达式 + /// + /// 左表达式 + /// 右表达式 + /// + public static Expression GreaterThan(this Expression left, Expression right) + { + return Expression.GreaterThan(left, right); + } + + /// + /// Lambda表达式 + /// + /// 类型 + /// 表达式 + /// 参数 + /// + public static Expression ToLambda(this Expression body, params ParameterExpression[] parameters) + { + return Expression.Lambda(body, parameters); + } + + /// + /// Lambda(真) + /// + /// 类型 + /// + public static Expression> True() { return param => true; } + + /// + /// Lambda(假) + /// + /// 类型 + /// + public static Expression> False() { return param => false; } + + /// + /// 组合And + /// + /// + public static Expression> And(this Expression> first, Expression> second) + { + return first.Compose(second, Expression.AndAlso); + } + + /// + /// 组合Or + /// + /// + public static Expression> Or(this Expression> first, Expression> second) + { + return first.Compose(second, Expression.OrElse); + } + + /// + /// Combines the first expression with the second using the specified merge function. + /// + private static Expression Compose(this Expression first, Expression second, Func merge) + { + var map = first.Parameters + .Select((f, i) => new { f, s = second.Parameters[i] }) + .ToDictionary(p => p.s, p => p.f); + var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body); + return Expression.Lambda(merge(first.Body, secondBody), first.Parameters); + } + + /// + /// ParameterRebinder + /// + private class ParameterRebinder : ExpressionVisitor + { + /// + /// The ParameterExpression map + /// + private readonly Dictionary map; + + /// + /// Initializes a new instance of the class. + /// + /// The map. + private ParameterRebinder(Dictionary map) + { + this.map = map ?? new Dictionary(); + } + + /// + /// Replaces the parameters. + /// + /// The map. + /// The exp. + /// Expression + public static Expression ReplaceParameters(Dictionary map, Expression exp) + { + return new ParameterRebinder(map).Visit(exp); + } + + /// + /// Visits the parameter. + /// + /// The p. + /// Expression + protected override Expression VisitParameter(ParameterExpression p) + { + if (map.TryGetValue(p, out ParameterExpression replacement)) + { + p = replacement; + } + return base.VisitParameter(p); + } + } + } +} \ No newline at end of file From a6fd02208208cbf0848e4229e8b0775fc8c2b7c9 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Wed, 16 Sep 2020 16:47:20 +0800 Subject: [PATCH 04/15] =?UTF-8?q?=E6=9B=B4=E6=96=B0mysql=E7=9A=84=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\244\350\241\214\346\226\207\346\241\243.txt" | 1 + ...ker\346\272\220\351\205\215\347\275\256.json" | 15 +++++++++++++++ .../mysql/docker-compose-mysql.yml" | 5 +++++ .../mysql/my.cnf" | 16 ++++++++++++++++ 4 files changed, 37 insertions(+) create mode 100644 "\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\345\221\275\344\273\244\350\241\214\346\226\207\346\241\243.txt" create mode 100644 "\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\346\272\220\351\205\215\347\275\256.json" diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\345\221\275\344\273\244\350\241\214\346\226\207\346\241\243.txt" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\345\221\275\344\273\244\350\241\214\346\226\207\346\241\243.txt" new file mode 100644 index 00000000..d1aac693 --- /dev/null +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\345\221\275\344\273\244\350\241\214\346\226\207\346\241\243.txt" @@ -0,0 +1 @@ +https://docs.docker.com/engine/reference/commandline/dockerd/ \ No newline at end of file diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\346\272\220\351\205\215\347\275\256.json" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\346\272\220\351\205\215\347\275\256.json" new file mode 100644 index 00000000..85934c9c --- /dev/null +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/docker\346\272\220\351\205\215\347\275\256.json" @@ -0,0 +1,15 @@ +{ + "registry-mirrors" : [ + "https://mirror.ccs.tencentyun.com", + "http://registry.docker-cn.com", + "http://docker.mirrors.ustc.edu.cn", + "http://hub-mirror.c.163.com", + "https://5hh8258g.mirror.aliyuncs.com" + ], + "insecure-registries" : [ + "registry.docker-cn.com", + "docker.mirrors.ustc.edu.cn" + ], + "debug" : true, + "experimental" : true +} \ No newline at end of file diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/docker-compose-mysql.yml" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/docker-compose-mysql.yml" index 98f5951b..25a0b3fb 100644 --- "a/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/docker-compose-mysql.yml" +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/docker-compose-mysql.yml" @@ -14,6 +14,7 @@ services: - "3306:3306" #端口 模式1:8080 主机随机->8080 模式2: 8080:8080 主机8080->8080 environment: #设置容器内的环境变量 会覆盖镜像中的环境变量 - MYSQL_ROOT_PASSWORD=123456 + # - TZ=Asia/Shanghai #expose: #- "80" #在不向主机发布端口的情况下公开端口 - 链接的服务只能访问这些端口。只能指定内部端口。 network_mode: "bridge" #网络模式 bridge、host、none、service:[service name] @@ -29,6 +30,10 @@ services: - type: bind source: ./logs target: /logs + + - type: bind + source: ./my.cnf + target: /etc/mysql/my.cnf deploy: #部署配置 diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/my.cnf" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/my.cnf" index 15adb3f2..d3181824 100644 --- "a/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/my.cnf" +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\351\205\215\347\275\256\346\250\241\347\211\210/Docker-Compose\351\205\215\347\275\256/mysql/my.cnf" @@ -5,6 +5,22 @@ default_authentication_plugin=mysql_native_password sql_mode=ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION lower_case_table_names=1 #忽略表名大小写 +explicit_defaults_for_timestamp=true #开启查询缓存 +#skip-grant-tables #数据库每次重启之后不要密码就可以连接数据库,适用于管理员忘记密码时的操作 + +max_allowed_packet = 6M +group_concat_max_len=102400 + +default-time-zone='+08:00' #设置mysql时区 + +#查询不启用缓存 +query_cache_type=0 +query_cache_size=0 +max_connections=1000 + +#general_log = on #是否纪录SQL情况 on为开启 off为关闭 + + [client] default-character-set=utf8 [mysql] From efb6805a688c1fb10860934d2326bf1fedb85386 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Wed, 16 Sep 2020 16:47:37 +0800 Subject: [PATCH 05/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0A34=5F=E4=BD=BF?= =?UTF-8?q?=E7=94=A8DispatchProxy=E4=BB=A3=E7=90=86=E9=9D=9E=E5=85=AC?= =?UTF-8?q?=E5=BC=80=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=9C=AA=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VerificationCore/VerificationTypeEnum.cs" | 1 + ...0\211\346\213\251\347\261\273\345\236\213.cs" | 2 +- ...5\254\345\274\200\346\216\245\345\217\243.cs" | 16 ++++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 "\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" index 8d5a25de..cba9f586 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" @@ -52,6 +52,7 @@ public enum VerificationTypeEnum A31_快速转换枚举为字典, A32_序列化时按字段选择类型, A33_快速判断Int是否存在数组, + A34_使用DispatchProxy代理非公开接口, #endregion 技术点 diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213.cs" index 0944edd1..8462252a 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213.cs" @@ -3,7 +3,7 @@ namespace 技术点验证 { - [VerifcationType(VerificationTypeEnum.A31_快速转换枚举为字典)] + [VerifcationType(VerificationTypeEnum.A32_序列化时按字段选择类型)] public class A32_序列化时按字段选择类型 : IVerification { public void Start(string[]? args) diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" new file mode 100644 index 00000000..0379f0ee --- /dev/null +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" @@ -0,0 +1,16 @@ +using System; +using Verification.Core; + +namespace 技术点验证 +{ + [VerifcationType(VerificationTypeEnum.A34_使用DispatchProxy代理非公开接口)] + public class A34_使用DispatchProxy代理非公开接口 : IVerification + { + public void Start(string[]? args) + { + //参考资料:https://www.cnblogs.com/lwqlun/p/11575686.html + + throw new NotImplementedException(); + } + } +} \ No newline at end of file From 6bece0b0ec3cdc86bc4d93542396a85e9248941d Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Thu, 17 Sep 2020 16:52:55 +0800 Subject: [PATCH 06/15] . --- ...3\345\222\214\345\267\245\345\205\267.txt" | 3 +- .../VerificationCore/VerificationTypeEnum.cs" | 1 + ...5\256True\346\210\226\346\230\257False.cs" | 40 +++++++++++++++++++ .../Program.cs" | 2 +- 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 "\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\344\270\211\346\226\271\347\261\273\345\272\223\345\222\214\345\267\245\345\205\267.txt" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\344\270\211\346\226\271\347\261\273\345\272\223\345\222\214\345\267\245\345\205\267.txt" index a98ecdb1..36bc356e 100644 --- "a/\345\244\207\344\273\275\350\265\204\346\226\231/\344\270\211\346\226\271\347\261\273\345\272\223\345\222\214\345\267\245\345\205\267.txt" +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\344\270\211\346\226\271\347\261\273\345\272\223\345\222\214\345\267\245\345\205\267.txt" @@ -47,7 +47,8 @@ 46. Masuit.Tools 勤快哥的工具类,包含各种工具代码 47. ExcelKit 群里nameof(鸡你太美) 开发的excel导入导出组件 48. EasyCaching 缓存组件,有多个提供程序 - +49. Z.EntityFramework.Plus.EFCore ef的扩展库,包括过滤器,缓存,提前查询,批量操作等EF扩展功能。 +50. SharpCompress 纯C#文件压缩操作库,支持unrar, un7zip, unzip, untar unbzip2, ungzip, unlzip --工具 1. 查看GC数据的工具:https://github.com/Microsoft/perfview#getting-perfview diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" index cba9f586..4b063590 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core/VerificationCore/VerificationTypeEnum.cs" @@ -53,6 +53,7 @@ public enum VerificationTypeEnum A32_序列化时按字段选择类型, A33_快速判断Int是否存在数组, A34_使用DispatchProxy代理非公开接口, + A35_ConfigureAwait配置True或是False, #endregion 技术点 diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" new file mode 100644 index 00000000..34d6c2fb --- /dev/null +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" @@ -0,0 +1,40 @@ +using System.Threading; +using System.Threading.Tasks; +using Verification.Core; + +namespace 技术点验证 +{ + [VerifcationType(VerificationTypeEnum.A35_ConfigureAwait配置True或是False)] + public class A35_ConfigureAwait配置True或是False : IVerification + { + public void Start(string[]? args) + { + var a = new Task(() => { }).GetAwaiter(); + var b = new Task(() => { }).ConfigureAwait(false).GetAwaiter(); + + var a1 = new Task(() => { }).ContinueWith(t => { }).GetAwaiter(); + + var taskScheduler = TaskScheduler.Current; + + var b1 = new Task(() => { }).ContinueWith(t => { }, TaskScheduler.FromCurrentSynchronizationContext()) + .GetAwaiter(); + } + + public void Teest(Task task, Task nextTask) + { + var currentSyncContext = SynchronizationContext.Current; + + return task.ContinueWith(() => + { + if (currentSyncContext == null) + { + return nextTask; + } + else + { + currentSyncContext.Post(() => nextTask, null); + } + }, TaskScheduler.Current); + } + } +} \ No newline at end of file diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" index 09a54791..18999797 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" @@ -8,7 +8,7 @@ public class Program public static void Main(string[]? args) { //开始验证 - VerificationHelper.StartVerification(VerificationTypeEnum.A33_快速判断Int是否存在数组, args); + VerificationHelper.StartVerification(VerificationTypeEnum.A35_ConfigureAwait配置True或是False, args); } } } \ No newline at end of file From ba975d91331a624b2eb01906625989df32cf8146 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Fri, 18 Sep 2020 14:10:56 +0800 Subject: [PATCH 07/15] =?UTF-8?q?=E5=AD=98=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../A34TestClassDefinition.cs" | 78 +++++++++++++++++++ ...54\345\274\200\346\216\245\345\217\243.cs" | 48 +++++++++++- ...5\256True\346\210\226\346\230\257False.cs" | 33 ++++---- .../Program.cs" | 2 +- 4 files changed, 140 insertions(+), 21 deletions(-) create mode 100644 "\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34TestClassDefinition.cs" diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34TestClassDefinition.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34TestClassDefinition.cs" new file mode 100644 index 00000000..5332d321 --- /dev/null +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34TestClassDefinition.cs" @@ -0,0 +1,78 @@ +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Reflection; + +namespace 技术点验证 +{ + /// + /// 定义一个公开的接口用于对外调用 + /// + public interface IPublicHello + { + string ShowHello(); + } + + public interface IOther + { + } + + public class PublicHello : IPublicHello + { + private readonly IOther other; + + public PublicHello(IOther other) + { + this.other = other; + } + + public string ShowHello() + { + throw new System.NotImplementedException(); + } + } + + public class PublicHelloProxy : DispatchProxy + { + public PublicHelloProxy() + { + //如果有IOC,就从IOC中或 + } + + protected override object Invoke(MethodInfo targetMethod, object[] args) + { + throw new System.NotImplementedException(); + } + } + + public class DemoCode : IStartupFilter + { + public static IPublicHello GlobalPublicHello; + + public Action Configure(Action next) + { + return builder => + { + next(builder); + DemoCode.GlobalPublicHello = builder.ApplicationServices.GetService(); + }; + } + } + + /// + /// 模拟最极端的接口定义和实现 + /// + public class A34HelloDefinition + { + private interface IHello + { + string ShowHello(); + } + + private class Hello : IHello + { + public string ShowHello() => "this is Hello Class's hello"; + } + } +} \ No newline at end of file diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" index 0379f0ee..5a53ad33 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243/A34_\344\275\277\347\224\250DispatchProxy\344\273\243\347\220\206\351\235\236\345\205\254\345\274\200\346\216\245\345\217\243.cs" @@ -1,16 +1,58 @@ -using System; +using CkTools; +using System; +using System.Collections.Generic; +using System.Reflection; using Verification.Core; namespace 技术点验证 { + public interface IIds + { + ICollection Ids { get; set; } + } + [VerifcationType(VerificationTypeEnum.A34_使用DispatchProxy代理非公开接口)] - public class A34_使用DispatchProxy代理非公开接口 : IVerification + public partial class A34_使用DispatchProxy代理非公开接口 : IVerification { public void Start(string[]? args) { //参考资料:https://www.cnblogs.com/lwqlun/p/11575686.html - throw new NotImplementedException(); + LinkAction.Start() + .Add(UseReflection) + .Add(UseDispatchProxy) + .BatchRun(); } + + /// + /// 使用反射 + /// + public void UseReflection() + { + Console.WriteLine("使用反射"); + + //查找非公开类型 + System.Type? helloType = Assembly.GetExecutingAssembly() + .GetType(name: "技术点验证.A34HelloDefinition+Hello", throwOnError: true) + ?? throw new TypeLoadException("未找到type信息"); + + //提取方法 + var methodInfo = helloType.GetMethod("ShowHello") ?? throw new TypeLoadException("未找到方法信息"); + + //调用 + var instanceObj = Activator.CreateInstance(helloType); + Console.WriteLine(methodInfo.Invoke(instanceObj, null)); + } + + public void UseDispatchProxy() + { + var testInterfaceObj = DispatchProxy.Create(); + _ = testInterfaceObj.Ids; + } + } + + public class AAA : IIds + { + public ICollection Ids { get; set; } } } \ No newline at end of file diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" index 34d6c2fb..a0a73f34 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False/A35_ConfigureAwait\351\205\215\347\275\256True\346\210\226\346\230\257False.cs" @@ -1,5 +1,4 @@ -using System.Threading; -using System.Threading.Tasks; +using System.Threading.Tasks; using Verification.Core; namespace 技术点验证 @@ -20,21 +19,21 @@ public void Start(string[]? args) .GetAwaiter(); } - public void Teest(Task task, Task nextTask) - { - var currentSyncContext = SynchronizationContext.Current; + //public Task Test(Task task, Task nextTask) + //{ + // var currentSyncContext = SynchronizationContext.Current; - return task.ContinueWith(() => - { - if (currentSyncContext == null) - { - return nextTask; - } - else - { - currentSyncContext.Post(() => nextTask, null); - } - }, TaskScheduler.Current); - } + // return task.ContinueWith(() => + // { + // if (currentSyncContext == null) + // { + // return nextTask; + // } + // else + // { + // currentSyncContext.Post(() => nextTask, null); + // } + // }, TaskScheduler.Current); + //} } } \ No newline at end of file diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" index 18999797..553fb51e 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/Program.cs" @@ -8,7 +8,7 @@ public class Program public static void Main(string[]? args) { //开始验证 - VerificationHelper.StartVerification(VerificationTypeEnum.A35_ConfigureAwait配置True或是False, args); + VerificationHelper.StartVerification(VerificationTypeEnum.A34_使用DispatchProxy代理非公开接口, args); } } } \ No newline at end of file From 9be8400bc84b3faa9f3992204b38c49ef2b34d32 Mon Sep 17 00:00:00 2001 From: hjkl950217 <584880422@qq.com> Date: Fri, 18 Sep 2020 17:23:22 +0800 Subject: [PATCH 08/15] temp --- .../123.ppx" | 108 +++++++ .../resharperSetting.DotSettings" | 277 ++++++++++++++++++ 2 files changed, 385 insertions(+) create mode 100644 "\345\244\207\344\273\275\350\265\204\346\226\231/123.ppx" create mode 100644 "\345\244\207\344\273\275\350\265\204\346\226\231/resharperSetting.DotSettings" diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/123.ppx" "b/\345\244\207\344\273\275\350\265\204\346\226\231/123.ppx" new file mode 100644 index 00000000..013a9f32 --- /dev/null +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/123.ppx" @@ -0,0 +1,108 @@ + + + + + + + + + %ComputerName%; localhost; *.local + + + + + + + + + + +
127.0.0.1
+ 1088 + 48 +
+
+ + + + ShadowsocksR-4.7-妹子最后一版.exe [auto-created] + ShadowsocksR-4.7-妹子最后一版.exe + + + + Localhost + localhost; 127.0.0.1; %ComputerName% + + + + 游戏 + steamerrorreporter64.exe; +steamerrorreporter.exe; +streaming_client.exe; +x86launcher.exe; +x64launcher.exel; +secure_desktop_capture.exe; +steam_monitor.exe; +html5app_steam.exe; +steamservice.exe; +steamwebhelper.exe; +GameOverlayUI.exe; +Steam.exe; +gldriverquery64.exe; +gldriverquery.exe; +wow_helper.exe; +WriteMiniDump.exe; + 101 + + + 瘟疫公司 + PlagueIncSC.exe;PlagueIncEvolved.exe; + 101 + + + 平时 + KuGou.exe;KGService.exe + 101 + + + 战争框架 + RemoteCrashSender.exe;warframe.exe; dwarframe.x64.exe;JiraClient.exe; Launcher.exe; remotecrashsender.exe;launchercef.exe;Warframe.x64.exe + 101 + + + 办公 + OneDrive.exe;OneNote.exe +Microsoft.Alm.Shared.Remoting.RemoteContainer.dll; + 101 + + + VS + devenv.exe;VSIXInstaller.exe;d + 101 + + + 异星工厂 + factorio.exe; + 101 + + + Dism++ + Dism++x64.exe;Dism++x86.exe;bcdboot.exe;bcdboot.exe + 101 + + + SoucreTree + SourceTreeUpdate.exe;SourceTree.exe;BsSndRpt.exe;Askpass.exe;stree_gri.exe;7za.exe;getopt.exe;pageant.exe;patch.exe;plink.exe;puttygen.exe + 101 + + + 上网规则 + *.*google*.*;*.*android*.*;*.*youtube*.*;www.youtube.com;youtube.*;*.youtube.*;*.*color-themes*.*;*.*seleniumhq*.*;*.*github*.*;goo.gl;*.githubusercontent.com; + 101 + + + Default + + + +
\ No newline at end of file diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/resharperSetting.DotSettings" "b/\345\244\207\344\273\275\350\265\204\346\226\231/resharperSetting.DotSettings" new file mode 100644 index 00000000..37edd552 --- /dev/null +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/resharperSetting.DotSettings" @@ -0,0 +1,277 @@ + + Disabled + False + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + DO_NOT_SHOW + <?xml version="1.0" encoding="utf-16"?> +<Patterns StaticFieldReorderingPolicy="Relaxed" xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> + <TypePattern DisplayName="Non-reorderable types"> + <TypePattern.Match> + <Or> + <And> + <Kind Is="Interface" /> + <Or> + <HasAttribute Name="System.Runtime.InteropServices.InterfaceTypeAttribute" /> + <HasAttribute Name="System.Runtime.InteropServices.ComImport" /> + </Or> + </And> + <Kind Is="Struct" /> + <HasAttribute Name="JetBrains.Annotations.NoReorderAttribute" /> + <HasAttribute Name="JetBrains.Annotations.NoReorder" /> + </Or> + </TypePattern.Match> + </TypePattern> + <TypePattern DisplayName="xUnit.net Test Classes" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <HasMember> + <And> + <Kind Is="Method" /> + <HasAttribute Name="Xunit.FactAttribute" Inherited="True" /> + <HasAttribute Name="Xunit.TheoryAttribute" Inherited="True" /> + </And> + </HasMember> + </And> + </TypePattern.Match> + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <Or> + <Kind Is="Constructor" /> + <And> + <Kind Is="Method" /> + <ImplementsInterface Name="System.IDisposable" /> + </And> + </Or> + </Entry.Match> + <Entry.SortBy> + <Kind Order="Constructor" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="All other members" /> + <Entry Priority="100" DisplayName="Test Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="Xunit.FactAttribute" /> + <HasAttribute Name="Xunit.TheoryAttribute" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + <TypePattern DisplayName="NUnit Test Fixtures" RemoveRegions="All"> + <TypePattern.Match> + <And> + <Kind Is="Class" /> + <Or> + <HasAttribute Name="NUnit.Framework.TestFixtureAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TestFixtureSourceAttribute" Inherited="True" /> + <HasMember> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" /> + <HasAttribute Name="NUnit.Framework.TestCaseAttribute" /> + <HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" /> + </And> + </HasMember> + </Or> + </And> + </TypePattern.Match> + <Entry DisplayName="Setup/Teardown Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <Or> + <HasAttribute Name="NUnit.Framework.SetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TearDownAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TestFixtureSetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.TestFixtureTearDownAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.OneTimeSetUpAttribute" Inherited="True" /> + <HasAttribute Name="NUnit.Framework.OneTimeTearDownAttribute" Inherited="True" /> + </Or> + </And> + </Entry.Match> + </Entry> + <Entry DisplayName="All other members" /> + <Entry Priority="100" DisplayName="Test Methods"> + <Entry.Match> + <And> + <Kind Is="Method" /> + <HasAttribute Name="NUnit.Framework.TestAttribute" /> + <HasAttribute Name="NUnit.Framework.TestCaseAttribute" /> + <HasAttribute Name="NUnit.Framework.TestCaseSourceAttribute" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + </TypePattern> + <TypePattern DisplayName="Default Pattern"> + <Entry Priority="100" DisplayName="Public Delegates"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Delegate" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + <Entry Priority="100" DisplayName="Public Enums"> + <Entry.Match> + <And> + <Access Is="Public" /> + <Kind Is="Enum" /> + </And> + </Entry.Match> + <Entry.SortBy> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Static Fields and Constants"> + <Entry.Match> + <Or> + <Kind Is="Constant" /> + <And> + <Kind Is="Field" /> + <Static /> + </And> + </Or> + </Entry.Match> + <Entry.SortBy> + <Kind Order="Constant Field" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Fields"> + <Entry.Match> + <And> + <Kind Is="Field" /> + <Not> + <Static /> + </Not> + </And> + </Entry.Match> + <Entry.SortBy> + <Readonly /> + <Name /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Constructors"> + <Entry.Match> + <Kind Is="Constructor" /> + </Entry.Match> + <Entry.SortBy> + <Static /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="Properties, Indexers"> + <Entry.Match> + <Or> + <Kind Is="Property" /> + <Kind Is="Indexer" /> + </Or> + </Entry.Match> + </Entry> + <Entry Priority="100" DisplayName="Interface Implementations"> + <Entry.Match> + <And> + <Kind Is="Member" /> + <ImplementsInterface /> + </And> + </Entry.Match> + <Entry.SortBy> + <ImplementsInterface Immediate="True" /> + </Entry.SortBy> + </Entry> + <Entry DisplayName="All other members" /> + <Entry DisplayName="Nested Types"> + <Entry.Match> + <Kind Is="Type" /> + </Entry.Match> + </Entry> + </TypePattern> +</Patterns> + True + False + False + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> + False + True + Disabled + True + False + False + DO_NOTHING + LIVE_MONITOR + LIVE_MONITOR + DO_NOTHING + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + LIVE_MONITOR + DO_NOTHING + LIVE_MONITOR + 9 + True + 09/18/2020 09:26:24 + False + False + False + True + True + True + True + True + anonymous + True + True + Features + True + 2020.2 + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file From ea4882fffc15d961f23b1d00b08788a9f1a96015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Tue, 29 Sep 2020 17:51:34 +0800 Subject: [PATCH 09/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0github=E5=B7=A5?= =?UTF-8?q?=E5=85=B7=E5=9C=B0=E5=9D=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\345\267\245\345\205\267-github\345\234\260\345\235\200.txt" | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 "\345\244\207\344\273\275\350\265\204\346\226\231/\345\267\245\345\205\267-github\345\234\260\345\235\200.txt" diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\345\267\245\345\205\267-github\345\234\260\345\235\200.txt" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\345\267\245\345\205\267-github\345\234\260\345\235\200.txt" new file mode 100644 index 00000000..eb87bd94 --- /dev/null +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\345\267\245\345\205\267-github\345\234\260\345\235\200.txt" @@ -0,0 +1,2 @@ +amd ryzen master vbs破解工具: https://github.com/klauspost/ryzen-master-vbs-patch +qbittorrent 增强版:https://github.com/c0re100/qBittorrent-Enhanced-Edition \ No newline at end of file From 02ef991c97e318cfd914cf943203686c972a6baf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Tue, 29 Sep 2020 17:51:38 +0800 Subject: [PATCH 10/15] . --- .../Verification.Core.Test/Verification.Core.Test.csproj" | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core.Test/Verification.Core.Test.csproj" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core.Test/Verification.Core.Test.csproj" index 06f8df7c..ad70927f 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core.Test/Verification.Core.Test.csproj" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/Verification.Core.Test/Verification.Core.Test.csproj" @@ -6,7 +6,7 @@ - + From 1f0cb81bde29878413747e0a54c0156e47c30626 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Wed, 14 Oct 2020 11:56:38 +0800 Subject: [PATCH 11/15] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B0=83=E8=AF=95?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...7\234\213body\345\206\205\345\256\271.txt" | 30 ++++++++++++++++++ ...3\347\232\204\347\237\245\350\257\206.txt" | Bin 6852 -> 7010 bytes 2 files changed, 30 insertions(+) create mode 100644 "\345\244\207\344\273\275\350\265\204\346\226\231/\344\273\243\347\240\201\347\211\207\346\256\265/\344\273\243\347\240\201-\344\273\216\344\270\255\351\227\264\344\273\266\346\237\245\347\234\213body\345\206\205\345\256\271.txt" diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\344\273\243\347\240\201\347\211\207\346\256\265/\344\273\243\347\240\201-\344\273\216\344\270\255\351\227\264\344\273\266\346\237\245\347\234\213body\345\206\205\345\256\271.txt" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\344\273\243\347\240\201\347\211\207\346\256\265/\344\273\243\347\240\201-\344\273\216\344\270\255\351\227\264\344\273\266\346\237\245\347\234\213body\345\206\205\345\256\271.txt" new file mode 100644 index 00000000..cb8a9790 --- /dev/null +++ "b/\345\244\207\344\273\275\350\265\204\346\226\231/\344\273\243\347\240\201\347\211\207\346\256\265/\344\273\243\347\240\201-\344\273\216\344\270\255\351\227\264\344\273\266\346\237\245\347\234\213body\345\206\205\345\256\271.txt" @@ -0,0 +1,30 @@ + #region 调试body内容 + + async Task GetResponse(HttpResponse response) + { + response.Body.Seek(0, SeekOrigin.Begin); + string text = await new StreamReader(response.Body).ReadToEndAsync(); + response.Body.Seek(0, SeekOrigin.Begin); + return text; + } + + app.Use(async (context, next) => + { + if (context.Request.Path.Value.Contains("/api/SensorDataUpLoad/DaLianShengShi_WaterMeter")) + { + Stream originStram = context.Response.Body; + using (MemoryStream resoponseBody = new MemoryStream()) + { + context.Response.Body = resoponseBody; + await next(); + string aaa = await GetResponse(context.Response); + await resoponseBody.CopyToAsync(originStram); + } + } + else + { + await next(); + } + }); + + #endregion 调试body内容 \ No newline at end of file diff --git "a/\345\244\207\344\273\275\350\265\204\346\226\231/\350\246\201\347\234\213\347\232\204\347\237\245\350\257\206.txt" "b/\345\244\207\344\273\275\350\265\204\346\226\231/\350\246\201\347\234\213\347\232\204\347\237\245\350\257\206.txt" index a3c6b44ba378872a474c49d2cd86f3b80b34a0fb..f0d5f1468cf4ee910555e80dad6d027a21bfad28 100644 GIT binary patch delta 167 zcmX?N`p9g<5vh7!1}+8=4q(VO@MTD3$YW4okZROPZz&V2pBWe)T@fhtKLaRN z!cYKIW5u8kgoz9(KplAu=|B-ZhGZZ+7c5!?RFw(j=P;xKW%L=07!1HzA4ppO`G!Cm iM4B>KGMF Date: Wed, 14 Oct 2020 11:57:00 +0800 Subject: [PATCH 12/15] =?UTF-8?q?=E4=BC=98=E5=8C=96string=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../BaseType/ByteExtensions.cs | 4 +- .../BaseType/ObjectExtensions.cs | 8 +- .../BaseType/StringExtensions.cs | 74 ++++++++----------- .../Helper/TypeConvertDelegate.cs | 8 +- .../TypeConvertExtension.cs | 12 +-- .../Entity/StepContextExtension.cs | 2 +- 6 files changed, 53 insertions(+), 55 deletions(-) diff --git a/CkTools/Src/CkTools.BaseExtensions/BaseType/ByteExtensions.cs b/CkTools/Src/CkTools.BaseExtensions/BaseType/ByteExtensions.cs index c040e430..7fdd921b 100644 --- a/CkTools/Src/CkTools.BaseExtensions/BaseType/ByteExtensions.cs +++ b/CkTools/Src/CkTools.BaseExtensions/BaseType/ByteExtensions.cs @@ -12,8 +12,8 @@ public static class ByteExtensions /// public static string ToStr(this byte[] source, Encoding? encoding = null) { - encoding = encoding ?? Encoding.UTF8; - return source.BaseConvertOrDefalut(string.Empty, encoding.GetString); + encoding ??= Encoding.UTF8; + return source.BaseConvertOrDefalut(encoding.GetString, string.Empty); } } } \ No newline at end of file diff --git a/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs b/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs index 62471d57..a089e152 100644 --- a/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs +++ b/CkTools/Src/CkTools.BaseExtensions/BaseType/ObjectExtensions.cs @@ -184,7 +184,7 @@ public static int ToInt32(this T str) public static int ToInt32OrDefault(this T str, int defaultValue = 0) where T : class { - return str.BaseConvertOrDefalut(defaultValue, System.Convert.ToInt32); + return str.BaseConvertOrDefalut(System.Convert.ToInt32, defaultValue); } public static bool ToBool(this T str) @@ -196,7 +196,7 @@ public static bool ToBool(this T str) public static bool ToBoolOrDefault(this T str, bool defaultValue = false) where T : class { - return str.BaseConvertOrDefalut(defaultValue, System.Convert.ToBoolean); + return str.BaseConvertOrDefalut(System.Convert.ToBoolean, defaultValue); } public static decimal ToDecimal(this T str) @@ -209,7 +209,7 @@ public static decimal ToDecimalOrDefault( this T str, decimal defaultValue = 0.00M) where T : class { - return str.BaseConvertOrDefalut(defaultValue, System.Convert.ToDecimal); + return str.BaseConvertOrDefalut(System.Convert.ToDecimal, defaultValue); } public static double ToDouble(this T str) @@ -222,7 +222,7 @@ public static double ToDoubleOrDefault( this T str, double defaultValue = 0.00) where T : class { - return str.BaseConvertOrDefalut(defaultValue, System.Convert.ToDouble); + return str.BaseConvertOrDefalut(System.Convert.ToDouble, defaultValue); } #endregion 基础类型与Object之间的转换 diff --git a/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs b/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs index d01d5750..0b622205 100644 --- a/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs +++ b/CkTools/Src/CkTools.BaseExtensions/BaseType/StringExtensions.cs @@ -84,7 +84,7 @@ public static int ToInt32(this string str) public static int ToInt32OrDefault(this string str, int defaultValue = 0) { - return str.TryBaseConvert(System.Convert.ToInt32, defaultValue); + return str.BaseConvertOrDefalut(System.Convert.ToInt32, defaultValue); } public static bool ToBool(this string str) @@ -94,7 +94,7 @@ public static bool ToBool(this string str) public static bool ToBoolOrDefault(this string str, bool defaultValue = false) { - return str.TryBaseConvert(System.Convert.ToBoolean, defaultValue); + return str.BaseConvertOrDefalut(System.Convert.ToBoolean, defaultValue); } public static decimal ToDecimal(this string str) @@ -106,7 +106,7 @@ public static decimal ToDecimalOrDefault( this string str, decimal defaultValue = 0.00M) { - return str.TryBaseConvert(System.Convert.ToDecimal, defaultValue); + return str.BaseConvertOrDefalut(System.Convert.ToDecimal, defaultValue); } public static double ToDouble(this string str) @@ -118,57 +118,47 @@ public static double ToDoubleOrDefault( this string str, double defaultValue = 0.00) { - return str.TryBaseConvert(System.Convert.ToDouble, defaultValue); + return str.BaseConvertOrDefalut(System.Convert.ToDouble, defaultValue); } public static long ToLong(this string str, long defaultValue = 0L) { - return str.TryBaseConvert(TypeConvertDelegate.stringToLong, defaultValue); + return str.BaseConvertOrDefalut(TypeConvertDelegate.stringToLong, defaultValue); } - /// - /// 基础转换,转换失败时会报错 - /// - /// - /// 要转换的字符串 - /// 转换的方法 - /// 类型为 的值 - /// The parameter 'str' is invalid、Empty、Null - private static TValue BaseConvert( - this string str, - Func convert) + public static DateTime ToLocalDateTime(this string str) { - Func convertTemp = t => { emptyWithException(t); return convert(t); }; - return str.BaseConvert(convertTemp); + return str.BaseConvert(TypeConvertDelegate.stringToLocalDateTime); } - /// - /// 基础转换,转换失败时会返回默认值 - /// - /// - /// 要转换的字符串 - /// 默认值 - /// 转换的方法 - /// 类型为 的值 - private static TValue TryBaseConvert( - this string str, - Func convert, - TValue defaultValue = default) - { - Func convertTemp = t => { emptyWithException(t); return convert(t); }; - return str.BaseConvertOrDefalut(defaultValue, convertTemp); - } + ///// + ///// 基础转换,转换失败时会返回默认值 + ///// + ///// + ///// 要转换的字符串 + ///// 默认值 + ///// 转换的方法 + ///// 类型为 的值 + ///// The parameter 'str' is invalid、Empty、Null + //private static TValue TryBaseConvert( + // this string str, + // Func convert, + // TValue defaultValue = default) + //{ + // Func convertTemp = t => { emptyWithException(t); return convert(t); }; + // return str.BaseConvertOrDefalut(defaultValue, convertTemp); + //} #region TryToDateTimeOffset /// /// 标准时间格式中包含的符号(用于和long区分使用) /// - private static string[] timeSysmbols = new string[] { ":", "+", "T", "Z", "-", "/" }; + private static readonly string[] timeSysmbols = new string[] { ":", "+", "T", "Z", "-", "/" }; public static DateTimeOffset TryToDateTimeOffset(this string str) { - return str.TryBaseConvert(TypeConvertDelegate.stringToDateTimeOffset); + return str.BaseConvertOrDefalut(TypeConvertDelegate.stringToDateTimeOffset, default(DateTimeOffset)); } public static DateTimeOffset TryToUtcDateTimeOffset(this string str) @@ -196,8 +186,8 @@ private static DateTimeOffset TryToDateTimeOffsetBase(this string str, Func DateTimeOffset.MinValue, - var a when a.ContainsSymbol(timeSysmbols) => str.TryBaseConvert(TypeConvertDelegate.stringToDateTimeOffset), - _ => str.TryBaseConvert(convert)//匹配不上则为long + var a when a.ContainsSymbol(timeSysmbols) => str.BaseConvertOrDefalut(TypeConvertDelegate.stringToDateTimeOffset, default(DateTimeOffset)), + _ => str.BaseConvertOrDefalut(convert, default(DateTimeOffset))//匹配不上则为long }; } @@ -290,7 +280,7 @@ public static string RemoveExtraSymbol(this string source, params char[] symbols ReadOnlySpan chars = source.AsSpan(); bool isExtra = false; - foreach (var item in symbols) + foreach (char item in symbols) { isExtra = chars[source.Length - 1] == item; if (isExtra == true) break; @@ -333,14 +323,14 @@ public static string SubstringExt(this string source, int length, int startIndex /// public static byte[] ToBytes(this string source, Encoding? encoding = null) { - encoding = encoding ?? Encoding.UTF8; - return source.BaseConvertOrDefalut(Array.Empty(), encoding.GetBytes); + encoding ??= Encoding.UTF8; + return source.BaseConvertOrDefalut(encoding.GetBytes, Array.Empty()); } public static T ToEnum(this string str, bool ignoreCase = false) where T : struct { - if (Enum.TryParse(str, ignoreCase, out var enumValue)) + if (Enum.TryParse(str, ignoreCase, out T enumValue)) { return enumValue; } diff --git a/CkTools/Src/CkTools.BaseExtensions/Helper/TypeConvertDelegate.cs b/CkTools/Src/CkTools.BaseExtensions/Helper/TypeConvertDelegate.cs index 10b44ed2..4680b94f 100644 --- a/CkTools/Src/CkTools.BaseExtensions/Helper/TypeConvertDelegate.cs +++ b/CkTools/Src/CkTools.BaseExtensions/Helper/TypeConvertDelegate.cs @@ -11,13 +11,17 @@ public static class TypeConvertDelegate public static Func utcToLocal = t => t.AddOffset(TimeZoneInfo.Local.BaseUtcOffset); public static Func localToUtc = t => t.AddOffset(-TimeZoneInfo.Local.BaseUtcOffset); - #endregion 基础转换 + public static Func longToDatetime => + ts => TimeZoneInfo.ConvertTime(new DateTime(1970, 1, 1), TimeZoneInfo.Local) + + TimeSpan.FromSeconds(ts); /// /// int转bool,大于0为true /// public static Func intToBool = t => t > 0 ? true : false; + #endregion 基础转换 + #region 组合转换 public static Func longStringToUtcDateTimeOffset = stringToLong @@ -34,6 +38,8 @@ public static class TypeConvertDelegate .Pipe(longToUtcDateTimeOffsetByMilliseconds) .Pipe(utcToLocal); + public static Func stringToLocalDateTime = stringToLong.Pipe(longToDatetime); + #endregion 组合转换 } } \ No newline at end of file diff --git a/CkTools/Src/CkTools.BaseExtensions/TypeConvertExtension.cs b/CkTools/Src/CkTools.BaseExtensions/TypeConvertExtension.cs index f749d1da..169d4ac7 100644 --- a/CkTools/Src/CkTools.BaseExtensions/TypeConvertExtension.cs +++ b/CkTools/Src/CkTools.BaseExtensions/TypeConvertExtension.cs @@ -18,10 +18,12 @@ public static TValue BaseConvert( this T source, Func convert) { - if (typeof(T).IsClass && source == null) + if (typeof(T).IsClass + && (source == null || source.GetHashCode() == string.Empty.GetHashCode())) { - throw new ArgumentException("The parameter 'str' is invalid、Empty、Null", nameof(source)); + throw new ArgumentException($"The parameter '{nameof(source)}' is invalid、Empty、Null", nameof(source)); } + return convert(source); } @@ -31,13 +33,13 @@ public static TValue BaseConvert( /// /// /// 要转换的字符串 - /// 默认值 /// 转换的方法 + /// 默认值 /// 类型为的值 public static TValue BaseConvertOrDefalut( this T source, - TValue defaultValue, - Func convert) + Func convert, + TValue defaultValue) { if (typeof(T).IsClass && source == null) { diff --git a/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs b/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs index 6a91957c..2eb8a7a5 100644 --- a/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs +++ b/CkTools/Src/CkTools.Nova/Entity/StepContextExtension.cs @@ -18,7 +18,7 @@ public static class StepContextExtension /// 能转换的前提是已经是类型的上下文了。 /// /// - public static StepContext As(this CkTools.Nova.Entity.StepContext taskContext) + public static StepContext? As(this StepContext taskContext) { return taskContext as StepContext; } From d64c4b7df705e38b788358389c5d13b1890a29f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Wed, 14 Oct 2020 14:46:43 +0800 Subject: [PATCH 13/15] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=87=AD=E5=91=B3?= =?UTF-8?q?=E9=81=93=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CkTools.Nova/Helper/LogicalChainHelper.cs | 30 +++-------------- .../Extensions/OperatorExtensionsTest.cs | 32 +++++++++---------- .../Aop/LogicChainStepAttributeTest.cs | 16 +++++----- .../ResponseConvertHanderBase.cs" | 12 +++---- 4 files changed, 34 insertions(+), 56 deletions(-) diff --git a/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs b/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs index 709601d9..f7000a53 100644 --- a/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs +++ b/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs @@ -29,7 +29,7 @@ public static class LogicalChainHelper public static IList<(TAttribute attribute, Type Type)> GetCustomAttributesByAssemblies(Func predicate) where TAttribute : Attribute { - var types = AppDomain.CurrentDomain.GetAssemblies() + List<(TAttribute Attribute, Type type)>? types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(i => { try @@ -44,29 +44,7 @@ public static class LogicalChainHelper .Where(predicate) .Select(type => (Attribute: type.GetCustomAttribute(false), type)) .Where(attr => attr.Attribute != null) - .ToList() - ; - - //var types = AppDomain.CurrentDomain.GetAssemblies() - // .SelectMany(i => - // { - // try - // { - // return i.GetExportedTypes(); - // } - // catch - // { - // return new Type[0]; - // } - // }) - // .Where(predicate) - // .SelectMany(type => type - // .GetCustomAttributes() - // .Select(attr => (attr, type) - // ) - - // ); - + .ToList(); return types; } @@ -131,12 +109,12 @@ public static StepEntity[] SortList( bool isAutoEnd = true) { //排序 一组接口内部排序 - var stepList = taskArray + StepEntity[]? stepList = taskArray .OrderBy(i => i.Attribute.StepEnumOrder) .ToArray(); StepEntity tempMw = stepList.First();//获取第一个中间件的引用 - foreach (var item in stepList) + foreach (StepEntity? item in stepList) { tempMw.StepInstanceObject.Next = item.StepInstanceObject; tempMw = item;//将指针移动到下一个 diff --git a/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/OperatorExtensionsTest.cs b/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/OperatorExtensionsTest.cs index 5c86875e..a624bf8c 100644 --- a/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/OperatorExtensionsTest.cs +++ b/CkTools/Test/CKTools.BaseExtensions.Test/Extensions/OperatorExtensionsTest.cs @@ -1,6 +1,8 @@ using System; using Xunit; +#pragma warning disable CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 + namespace CKTools.BaseExtensions.Test.Extensions { public class OperatorExtensionsTest @@ -8,7 +10,7 @@ public class OperatorExtensionsTest public class TestEntity { public int A { get; set; } = 10; - public string B { get; set; } + public string? B { get; set; } } public class GetDataOrDefaultTest @@ -20,7 +22,7 @@ public void Two_Work_WithNoException() { TestEntity testEntity = new TestEntity(); int hashCode = testEntity.GetHashCode(); - var result = testEntity.GetDataOrDefault(getData: t => t, defaultValueFunc: () => new TestEntity()); + TestEntity? result = testEntity.GetDataOrDefault(getData: t => t, defaultValueFunc: () => new TestEntity()); Assert.Equal(hashCode, result.GetHashCode()); } @@ -28,8 +30,8 @@ public void Two_Work_WithNoException() [Fact] public void Two_DataIsNull_WithNoException() { - TestEntity testEntity = null; - var result = testEntity.GetDataOrDefault(getData: t => t, defaultValueFunc: () => new TestEntity()); + TestEntity? testEntity = null; + TestEntity? result = testEntity.GetDataOrDefault(getData: t => t, defaultValueFunc: () => new TestEntity()); Assert.NotNull(result); } @@ -37,15 +39,15 @@ public void Two_DataIsNull_WithNoException() [Fact] public void Two_DataIsNullAndIntPropertyIsNull_WithNoException() { - TestEntity testEntity = null; - var result = testEntity.GetDataOrDefault(getData: t => t.A, defaultValueFunc: () => 1); + TestEntity? testEntity = null; + int result = testEntity.GetDataOrDefault(getData: t => t.A, defaultValueFunc: () => 1); } [Fact] public void Two_DataIsNullAndStringPropertyIsNull_WithNoException() { - TestEntity testEntity = null; - var result = testEntity.GetDataOrDefault(getData: t => t.B, defaultValueFunc: () => string.Empty); + TestEntity? testEntity = null; + string? result = testEntity.GetDataOrDefault(getData: t => t.B, defaultValueFunc: () => string.Empty); Assert.NotNull(result); } @@ -55,7 +57,7 @@ public void Two_GetDataIsNull_WithException() { TestEntity testEntity = new TestEntity(); - var ex = Assert.Throws(() => + ArgumentNullException? ex = Assert.Throws(() => { _ = testEntity.GetDataOrDefault(getData: null, defaultValueFunc: () => new TestEntity()); }); @@ -68,7 +70,7 @@ public void Two_DefaultValueFunc_WithException() { TestEntity testEntity = new TestEntity(); - var ex = Assert.Throws(() => + ArgumentNullException? ex = Assert.Throws(() => { _ = testEntity.GetDataOrDefault(getData: t => t, defaultValueFunc: null); }); @@ -83,7 +85,7 @@ public void Two_DefaultValueFunc_WithException() [Fact] public void One_DataIsNull_WithNoException() { - TestEntity testEntity = null; + TestEntity? testEntity = null; _ = testEntity.GetDataOrDefault(getData: t => t, defaultValue: new TestEntity()); } @@ -92,7 +94,7 @@ public void One_GetDataIsNull_WithException() { TestEntity testEntity = new TestEntity(); - var ex = Assert.Throws(() => + ArgumentNullException? ex = Assert.Throws(() => { _ = testEntity.GetDataOrDefault(getData: null, defaultValue: new TestEntity()); }); @@ -103,8 +105,6 @@ public void One_GetDataIsNull_WithException() #endregion 一个委托的版本 } } +} - public class FPExtensionTest - { - } -} \ No newline at end of file +#pragma warning restore CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 \ No newline at end of file diff --git a/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs b/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs index f8bb8b02..30292685 100644 --- a/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs +++ b/CkTools/Test/CkTools.Nova.Test/Aop/LogicChainStepAttributeTest.cs @@ -14,7 +14,7 @@ public class LogicChainStepAttributeTest [Fact] public void Construction_One_Parameter() { - var result = new StepAttribute(TestTaskEnum.Start); + StepAttribute? result = new StepAttribute(TestTaskEnum.Start); Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); @@ -25,7 +25,7 @@ public void Construction_One_Parameter() [Fact] public void Construction_Two_Parameter() { - var result = new StepAttribute(TestTaskEnum.Start, ServiceLifetime.Scoped); + StepAttribute? result = new StepAttribute(TestTaskEnum.Start, ServiceLifetime.Scoped); Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); @@ -36,7 +36,7 @@ public void Construction_Two_Parameter() [Fact] public void Construction_Two_Parameter2() { - var result = new StepAttribute(TestTaskEnum.Start, typeof(TestResult)); + StepAttribute? result = new StepAttribute(TestTaskEnum.Start, typeof(TestResult)); Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); @@ -48,7 +48,7 @@ public void Construction_Two_Parameter2() [Fact] public void Construction_Three_Parameter() { - var result = new StepAttribute(TestTaskEnum.Start, typeof(TestResult), ServiceLifetime.Transient); + StepAttribute? result = new StepAttribute(TestTaskEnum.Start, typeof(TestResult), ServiceLifetime.Transient); Assert.Equal(typeof(TestTaskEnum), result.StepEnumType); Assert.Equal((int)TestTaskEnum.Start, result.StepEnumOrder); @@ -60,24 +60,24 @@ public void Construction_Three_Parameter() [Fact] public void Construction_stepEnumTypeValue_Null() { - var ex = Assert.Throws(() => + ArgumentNullException? ex = Assert.Throws(() => { #pragma warning disable CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 _ = new StepAttribute(null, typeof(TestResult)); #pragma warning restore CS8625 // 无法将 null 文本转换为不可为 null 的引用类型。 }); - Assert.Null(ex); + Assert.NotNull(ex); } [Fact] public void Construction_stepEnumTypeValue_NoEnum() { - var ex = Assert.Throws(() => + TypeAccessException? ex = Assert.Throws(() => { _ = new StepAttribute(123, typeof(TestResult)); }); - Assert.Null(ex); + Assert.NotNull(ex); } #endregion Construction method diff --git "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/DataConvertHander/ResponseConvertHanderBase.cs" "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/DataConvertHander/ResponseConvertHanderBase.cs" index fe81c1c7..34d21feb 100644 --- "a/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/DataConvertHander/ResponseConvertHanderBase.cs" +++ "b/\346\212\200\346\234\257\347\202\271\344\270\216\350\257\255\346\263\225/\346\212\200\346\234\257\347\202\271\351\252\214\350\257\201/A32_\345\272\217\345\210\227\345\214\226\346\227\266\346\214\211\345\255\227\346\256\265\351\200\211\346\213\251\347\261\273\345\236\213/DataConvertHander/ResponseConvertHanderBase.cs" @@ -45,13 +45,13 @@ public IEnumerable Parse(TDataSource dataSource) if (dataSource.IsNullOrEmpty()) return Array.Empty(); - var initFunc = this.outPutInitializer.Currying()(dataSource)(this.HanderType); + Func? initFunc = this.outPutInitializer.Currying()(dataSource)(this.HanderType); - var result = ArrayHelper.GetArray( + TOutPut[]? result = ArrayHelper.GetArray( count: this.fieldTypes.Length, createFactory: initFunc); - for (int i = 0 ; i < this.fieldTypes.Length ; i++) + for (int i = 0; i < this.fieldTypes.Length; i++) { result[i] = this.outPutSetter(dataSource, this.fieldTypes[i], result[i]); } @@ -60,19 +60,19 @@ public IEnumerable Parse(TDataSource dataSource) } /// - /// [重写]由子类重写,指示针对什么类型处理 + /// [由子类重写]指示针对什么类型处理 /// /// public abstract TType SetHanderType(); /// - /// [重写]由子类重写,指示针对什么数据类型处理 + /// [由子类重写]指示针对什么数据类型处理 /// /// public abstract IEnumerable SetFieldTypes(); /// - /// [重写]由子类重写,指示如何初始化返回结果 + /// [由子类重写]指示如何初始化返回结果 /// protected abstract Func SetOutPutInitializer(); From d6327f4153fb4e677df82571b8259c8e9fee16fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Thu, 29 Oct 2020 17:23:17 +0800 Subject: [PATCH 14/15] =?UTF-8?q?=E4=BF=AE=E5=A4=8DUT=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Factory/LogicalChainFactory.cs | 20 +++++++++++-------- .../CkTools.Nova/Helper/LogicalChainHelper.cs | 4 ++-- CkTools/Src/CkTools.Nova/LogicChain/IStep.cs | 2 +- .../Src/CkTools.Nova/LogicChain/StepBase.cs | 2 +- .../LogicChain/StepBaseGeneric.cs | 2 +- CkTools/Src/CkTools/CkTools.csproj | 3 +-- 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs b/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs index d84f42a6..b0596317 100644 --- a/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs +++ b/CkTools/Src/CkTools.Nova/Factory/LogicalChainFactory.cs @@ -37,7 +37,7 @@ public NovaFactory(IServiceProvider serviceProvider, List taskList) { this.di = serviceProvider; - var tempTaskList = this.GetNovaList(taskList); + Dictionary? tempTaskList = this.GetNovaList(taskList); this.taskList = new ConcurrentDictionary(tempTaskList); } @@ -46,7 +46,7 @@ public NovaFactory(IServiceProvider serviceProvider, List taskList) ///
/// /// - public IStep GetFirstTask() + public IStep? GetFirstTask() { StepEntity[] taskEntity = this.taskList.GetOrAdd( typeof(TEnumType), @@ -103,7 +103,7 @@ private StepEntity[] GetTaskEntity(Type enumType) //3.排序-排列接口上的Next //分组-以type为索引 - var taskGroup = tempTaskList.FindAll(t => t.Attribute.StepEnumType == enumType); + List? taskGroup = tempTaskList.FindAll(t => t.Attribute.StepEnumType == enumType); //排列next属性 return LogicalChainHelper.SortList(taskGroup); @@ -120,7 +120,7 @@ private List A_FindAllTaskEntity() private List B_CreateInstance(in List taskList, IServiceProvider di) { - foreach (var item in taskList) + foreach (StepEntity? item in taskList) { item.StepInstanceObject = this.CreateInstance(item.StepType, di); } @@ -134,13 +134,13 @@ private List B_CreateInstance(in List taskList, IService /// private Dictionary C_SortAndPermutation(in List taskList) { - var taskGroup = taskList + ILookup? taskGroup = taskList .ToLookup(t => t.Attribute.StepEnumType); Dictionary result = new Dictionary(); - foreach (var item in taskGroup) + foreach (IGrouping? item in taskGroup) { - var temp = LogicalChainHelper.SortList(item.ToList()); + StepEntity[]? temp = LogicalChainHelper.SortList(item.ToList()); result.Add(item.Key, temp); } @@ -152,6 +152,8 @@ private Dictionary C_SortAndPermutation(in List #region 创建实例 +#pragma warning disable CS8603 // 可能的 null 引用返回。 + /// ///(适合构造方法无参数) 利用框架自带的激活器创建实例. /// @@ -173,11 +175,13 @@ private TInstance CreateInstance(Type type, IServiceProvider di) private TInstance CreateInstance(Type type, params object[] args) where TInstance : class, new() { - TInstance tempInstance = Activator.CreateInstance(type, args) as TInstance;//利用这个自带的激活器创建,也可以修改为DI实例 + TInstance? tempInstance = Activator.CreateInstance(type, args) as TInstance;//利用这个自带的激活器创建,也可以修改为DI实例 return tempInstance; } +#pragma warning restore CS8603 // 可能的 null 引用返回。 + #endregion 创建实例 } } \ No newline at end of file diff --git a/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs b/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs index f7000a53..664727b0 100644 --- a/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs +++ b/CkTools/Src/CkTools.Nova/Helper/LogicalChainHelper.cs @@ -57,7 +57,7 @@ public static List FindAllTaskEntity() Func func = i => { return i.IsClass //类 - && i.IsEnum //枚举 + //&& i.IsEnum //枚举 && i.IsPublic //公共的 //&& i.IsGenericType == false //泛型类型 // && i.IsGenericTypeDefinition == false//泛型具体实现 @@ -87,7 +87,7 @@ public static List FindAllTaskEntity() /// 传递false时会自动附加一个空的以防止空指针异常 /// /// 排好顺序后,第一个可执行的 - public static IStep Sort( + public static IStep? Sort( IEnumerable taskArray, bool isAutoEnd = true) { diff --git a/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs b/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs index 61106405..c1a30cfb 100644 --- a/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs +++ b/CkTools/Src/CkTools.Nova/LogicChain/IStep.cs @@ -15,7 +15,7 @@ public interface IStep /// /// 由中排序或初始化时统一指定 /// - IStep Next { get; set; } + IStep? Next { get; set; } /// /// 异步执行任务 diff --git a/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs b/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs index ab28c5ee..ed7a918a 100644 --- a/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs +++ b/CkTools/Src/CkTools.Nova/LogicChain/StepBase.cs @@ -6,7 +6,7 @@ namespace CkTools.Nova.LogicChain { public abstract class StepBase : IStep { - public IStep Next { get; set; } + public IStep? Next { get; set; } public StepContext Context { get; set; } diff --git a/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs b/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs index 7d1345b9..edc4d0b6 100644 --- a/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs +++ b/CkTools/Src/CkTools.Nova/LogicChain/StepBaseGeneric.cs @@ -6,7 +6,7 @@ namespace CkTools.Nova.LogicChain { public abstract class StepBase : StepBase, IStep { - public new IStep Next { get; set; } + public new IStep? Next { get; set; } public new StepContext Context { get; set; } public Task InvokeAsync(StepContext context) diff --git a/CkTools/Src/CkTools/CkTools.csproj b/CkTools/Src/CkTools/CkTools.csproj index e3bc79c6..1c46174d 100644 --- a/CkTools/Src/CkTools/CkTools.csproj +++ b/CkTools/Src/CkTools/CkTools.csproj @@ -4,8 +4,7 @@ netstandard2.1 - 8.0 - enable + 包含一些扩展方法、工具类、FP扩展代码,欢迎讨论,项目地址: https://github.com/hjkl950217/learningTest https://github.com/hjkl950217/learningTest https://github.com/hjkl950217/learningTest From c036e674406558a4f2e2d8dc1586546b25d7cf58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=95=BF=E7=A9=BAX?= <584880422@qq.com> Date: Thu, 29 Oct 2020 17:23:24 +0800 Subject: [PATCH 15/15] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CkTools/Src/SDKPulishNuget.targets | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/CkTools/Src/SDKPulishNuget.targets b/CkTools/Src/SDKPulishNuget.targets index 643379fe..ead1df12 100644 --- a/CkTools/Src/SDKPulishNuget.targets +++ b/CkTools/Src/SDKPulishNuget.targets @@ -8,14 +8,13 @@ Github logo.png $(AssemblyName) - 包含一些扩展方法、工具类、FP扩展代码,欢迎讨论,项目地址: https://github.com/hjkl950217/learningTest - 8.0 - enable CkTools + enable + 8.0 $(VersionSuffix) - 3.1.0.8 + 3.1.0.9 $(Version)$(VersionSuffix) $(Version) $(Version)