diff --git a/.husky/commit-msg b/.husky/commit-msg index 764265f1..32539ddd 100644 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,8 +1,8 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -dotnet tool update -g dotnet-execute --prerelease -dotnet husky run --name "commit-message-linter" --args "$1" +# dotnet tool update -g dotnet-execute --prerelease +# dotnet husky run --name "commit-message-linter" --args "$1" echo echo Great work! 🥂 diff --git a/.husky/scripts/commit-lint.cs b/.husky/scripts/commit-lint.cs index 8a7500cc..a3c0850f 100644 --- a/.husky/scripts/commit-lint.cs +++ b/.husky/scripts/commit-lint.cs @@ -9,7 +9,10 @@ A simple regex commit linter var msg = File.ReadAllLines(args[0])[0]; Console.WriteLine("Your commit headline message is:\n> {0}", msg); if (System.Text.RegularExpressions.Regex.IsMatch(msg, pattern)) - return 0; + return 0; + +if (msg.StartsWith("Merge branch ")) + return 0; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Invalid commit message"); diff --git a/LICENSE b/LICENSE index a29d1281..c5d2a42c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,201 @@ -MIT License - -Copyright (c) 2017-2019 liweihan - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 WeihanLi + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 65084f23..50f2acf0 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,9 @@ [![WeihanLi.Common Latest](https://img.shields.io/nuget/vpre/WeihanLi.Common)](https://www.nuget.org/packages/WeihanLi.Common/absoluteLatest) -[![Pipelines Build Status](https://weihanli.visualstudio.com/Pipelines/_apis/build/status/WeihanLi.WeihanLi.Common?branchName=dev)](https://weihanli.visualstudio.com/Pipelines/_build/latest?definitionId=16&branchName=dev) +[![Azure Pipelines Build Status](https://weihanli.visualstudio.com/Pipelines/_apis/build/status/WeihanLi.WeihanLi.Common?branchName=dev)](https://weihanli.visualstudio.com/Pipelines/_build/latest?definitionId=16&branchName=dev) -[![Github Build Status](https://github.com/WeihanLi/WeihanLi.Common/workflows/dotnetcore/badge.svg?branch=dev)](https://github.com/WeihanLi/WeihanLi.Common/actions?query=workflow%3Adotnetcore+branch%3Adev) +[![Github Actions Build Status](https://github.com/WeihanLi/WeihanLi.Common/actions/workflows/default.yml/badge.svg)](https://github.com/WeihanLi/WeihanLi.Common/actions/workflows/default.yml) ## Intro diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e06a5a3d..19297e62 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,3 +36,11 @@ steps: displayName: 'Powershell Script' env: Nuget__ApiKey: $(nugetApiKey) + +# Publish code coverage results v2 +# Publish any of the code coverage results from a build. +- task: PublishCodeCoverageResults@2 + inputs: + summaryFileLocation: "$(System.DefaultWorkingDirectory)/**/coverage.cobertura.xml" # string. Required. Path to summary files. + #pathToSources: # string. Path to Source files. + #failIfCoverageEmpty: false # boolean. Fail if code coverage results are missing. Default: false. \ No newline at end of file diff --git a/build/build.cs b/build/build.cs index 87122eb9..fa0d064d 100644 --- a/build/build.cs +++ b/build/build.cs @@ -51,7 +51,7 @@ await BuildProcess.CreateBuilder() { foreach (var project in testProjects) { - await ExecuteCommandAsync($"dotnet test {project}"); + await ExecuteCommandAsync($"dotnet test --collect:\"XPlat Code Coverage;Format=cobertura,opencover;ExcludeByAttribute=ExcludeFromCodeCoverage,Obsolete,GeneratedCode,CompilerGeneratedAttribute\" {project}"); } }) ; diff --git a/build/version.props b/build/version.props index 85f81377..2c44b46c 100644 --- a/build/version.props +++ b/build/version.props @@ -2,7 +2,7 @@ 1 0 - 61 + 62 $(VersionMajor).$(VersionMinor).$(VersionPatch) diff --git a/samples/AspNetCoreSample/Events/EventConsumer.cs b/samples/AspNetCoreSample/Events/EventConsumer.cs index c63fc92b..aa997819 100644 --- a/samples/AspNetCoreSample/Events/EventConsumer.cs +++ b/samples/AspNetCoreSample/Events/EventConsumer.cs @@ -3,16 +3,12 @@ namespace AspNetCoreSample.Events; -public class EventConsumer : BackgroundService +public class EventConsumer + (IEventQueue eventQueue, IEventHandlerFactory eventHandlerFactory) + : BackgroundService { - private readonly IEventQueue _eventQueue; - private readonly IEventHandlerFactory _eventHandlerFactory; - - public EventConsumer(IEventQueue eventQueue, IEventHandlerFactory eventHandlerFactory) - { - _eventQueue = eventQueue; - _eventHandlerFactory = eventHandlerFactory; - } + private readonly IEventQueue _eventQueue = eventQueue; + private readonly IEventHandlerFactory _eventHandlerFactory = eventHandlerFactory; protected override async Task ExecuteAsync(CancellationToken stoppingToken) { diff --git a/samples/AspNetCoreSample/FluentAspectsServiceProviderFactory.cs b/samples/AspNetCoreSample/FluentAspectsServiceProviderFactory.cs index a4e54e70..543d962d 100644 --- a/samples/AspNetCoreSample/FluentAspectsServiceProviderFactory.cs +++ b/samples/AspNetCoreSample/FluentAspectsServiceProviderFactory.cs @@ -4,22 +4,15 @@ namespace AspNetCoreSample; -internal sealed class FluentAspectsServiceProviderFactory : IServiceProviderFactory +internal sealed class FluentAspectsServiceProviderFactory( + Action? optionsAction, + Action? aspectBuildAction, + Expression>? ignoreTypesPredict + ) : IServiceProviderFactory { - private readonly Action? _optionsAction; - private readonly Action? _aspectBuildAction; - private readonly Expression>? _ignoreTypesPredict; - - public FluentAspectsServiceProviderFactory( - Action? optionsAction, - Action? aspectBuildAction, - Expression>? ignoreTypesPredict - ) - { - _optionsAction = optionsAction; - _aspectBuildAction = aspectBuildAction; - _ignoreTypesPredict = ignoreTypesPredict; - } + private readonly Action? _optionsAction = optionsAction; + private readonly Action? _aspectBuildAction = aspectBuildAction; + private readonly Expression>? _ignoreTypesPredict = ignoreTypesPredict; public IServiceCollection CreateBuilder(IServiceCollection services) { @@ -39,15 +32,12 @@ public static IHostBuilder UseFluentAspectsServiceProviderFactory(this IHostBuil Action? aspectBuildAction = null, Expression>? ignoreTypesPredict = null) { - if (ignoreTypesPredict == null) - { - ignoreTypesPredict = t => + ignoreTypesPredict ??= t => t.HasNamespace() && (t.Namespace!.StartsWith("Microsoft.") || t.Namespace.StartsWith("System.") ) ; - } hostBuilder.UseServiceProviderFactory( new FluentAspectsServiceProviderFactory(optionsAction, aspectBuildAction, ignoreTypesPredict) ); diff --git a/samples/AspNetCoreSample/Startup.cs b/samples/AspNetCoreSample/Startup.cs index c277e057..9d14f57f 100644 --- a/samples/AspNetCoreSample/Startup.cs +++ b/samples/AspNetCoreSample/Startup.cs @@ -4,14 +4,9 @@ namespace AspNetCoreSample; -public class Startup +public class Startup(IConfiguration configuration) { - public Startup(IConfiguration configuration) - { - Configuration = configuration.ReplacePlaceholders(); - } - - public IConfiguration Configuration { get; } + public IConfiguration Configuration { get; } = configuration.ReplacePlaceholders(); // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) diff --git a/samples/DotNetCoreSample/AppHostTest.cs b/samples/DotNetCoreSample/AppHostTest.cs index 98d9741f..ce6ad1df 100644 --- a/samples/DotNetCoreSample/AppHostTest.cs +++ b/samples/DotNetCoreSample/AppHostTest.cs @@ -45,12 +45,8 @@ protected override Task ExecuteTaskAsync(CancellationToken stoppingToken) } } -file sealed class DiagnosticBackgroundService : CronBasedBackgroundServiceWithDiagnostic +file sealed class DiagnosticBackgroundService(IServiceProvider serviceProvider) : CronBasedBackgroundServiceWithDiagnostic(serviceProvider) { - public DiagnosticBackgroundService(IServiceProvider serviceProvider) : base(serviceProvider) - { - } - protected override string CronExpression => CronHelper.Secondly; protected override Task ExecuteTaskInternalAsync(IServiceProvider serviceProvider, CancellationToken stoppingToken) @@ -83,16 +79,11 @@ file interface IWebServer Task StopAsync(CancellationToken cancellationToken); } -file sealed class HttpListenerWebServer : IWebServer +file sealed class HttpListenerWebServer(IServiceProvider serviceProvider) : IWebServer { - private readonly IServiceProvider _serviceProvider; + private readonly IServiceProvider _serviceProvider = serviceProvider; private readonly HttpListener _listener = new(); - public HttpListenerWebServer(IServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } - public async Task StartAsync(CancellationToken cancellationToken) { _listener.Prefixes.Add("http://localhost:5100/"); @@ -127,14 +118,9 @@ public Task StopAsync(CancellationToken cancellationToken) } } -file sealed class WebServerHostedService : BackgroundService +file sealed class WebServerHostedService(IWebServer server) : BackgroundService { - private readonly IWebServer _server; - - public WebServerHostedService(IWebServer server) - { - _server = server; - } + private readonly IWebServer _server = server; public override async Task StopAsync(CancellationToken cancellationToken) { diff --git a/samples/DotNetCoreSample/AspectTest.cs b/samples/DotNetCoreSample/AspectTest.cs index 6223e1a8..4155690e 100644 --- a/samples/DotNetCoreSample/AspectTest.cs +++ b/samples/DotNetCoreSample/AspectTest.cs @@ -6,12 +6,8 @@ namespace DotNetCoreSample; -public class TestDbContext : DbContext +public class TestDbContext(DbContextOptions dbContextOptions) : DbContext(dbContextOptions) { - public TestDbContext(DbContextOptions dbContextOptions) : base(dbContextOptions) - { - } - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { // optionsBuilder.UseSqlServer(DbConnectionString); diff --git a/samples/DotNetCoreSample/DataExtensionTest.cs b/samples/DotNetCoreSample/DataExtensionTest.cs index d997321e..213644f0 100644 --- a/samples/DotNetCoreSample/DataExtensionTest.cs +++ b/samples/DotNetCoreSample/DataExtensionTest.cs @@ -36,13 +36,12 @@ [Token] [NVARCHAR](200) NULL, public static void MainTest() { var connString = DependencyResolver.ResolveRequiredService().GetConnectionString("TestDb"); - using (var conn = new SqlConnection(connString)) - { - Init(conn); + using var conn = new SqlConnection(connString); + Init(conn); - for (int i = 0; i < 3; i++) - { - conn.Execute(@"INSERT INTO [dbo].[TestTable111] + for (var i = 0; i < 3; i++) + { + conn.Execute(@"INSERT INTO [dbo].[TestTable111] ( [Token], [CreatedTime] @@ -51,17 +50,17 @@ public static void MainTest() (@Token, --Token - nvarchar(200) @CreatedTime-- CreatedTime - datetime )", new TestEntity - { - Token = Guid.NewGuid().ToString("N") + "_Execute_Model", - CreatedTime = DateTime.Now - }); - } + { + Token = Guid.NewGuid().ToString("N") + "_Execute_Model", + CreatedTime = DateTime.Now + }); + } - Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); + Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); - for (int i = 0; i < 3; i++) - { - conn.Execute(@"INSERT INTO [dbo].[TestTable111] + for (var i = 0; i < 3; i++) + { + conn.Execute(@"INSERT INTO [dbo].[TestTable111] ( [Token], [CreatedTime] @@ -70,16 +69,16 @@ public static void MainTest() (@Token, --Token - nvarchar(200) GETDATE()-- CreatedTime - datetime )", new TestEntity - { - Token = Guid.NewGuid().ToString("N") + "_Execute_Model_1" - }); - } + { + Token = Guid.NewGuid().ToString("N") + "_Execute_Model_1" + }); + } - Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); + Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); - for (int i = 0; i < 3; i++) - { - conn.Execute(@"INSERT INTO [dbo].[TestTable111] + for (var i = 0; i < 3; i++) + { + conn.Execute(@"INSERT INTO [dbo].[TestTable111] ( [Token], [CreatedTime] @@ -88,35 +87,34 @@ public static void MainTest() (@Token, --Token - nvarchar(200) GETDATE()-- CreatedTime - datetime )", new - { - Token = Guid.NewGuid().ToString("N") + "_Execute_Anonymous_Model" - }); - } - - Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); + { + Token = Guid.NewGuid().ToString("N") + "_Execute_Anonymous_Model" + }); + } - var tokens = conn.QueryColumn("SELECT Token FROM [dbo].[TestTable111]"); - Console.WriteLine("tokens:{0}", string.Join(",", tokens)); + Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); - var ids = conn.Select("SELECT PKID FROM [dbo].[TestTable111]"); - Console.WriteLine("ids:{0}", string.Join(",", ids)); + var tokens = conn.QueryColumn("SELECT Token FROM [dbo].[TestTable111]"); + Console.WriteLine("tokens:{0}", string.Join(",", tokens)); - var lastId = conn.Fetch("SELECT TOP 1 PKID FROM [dbo].[TestTable111] ORDER BY PKID DESC"); - Console.WriteLine("lastId:{0}", lastId); + var ids = conn.Select("SELECT PKID FROM [dbo].[TestTable111]"); + Console.WriteLine("ids:{0}", string.Join(",", ids)); - conn.Execute("Delete from TestTable111 where PKID > @pkid", new { pkid = 888 }); + var lastId = conn.Fetch("SELECT TOP 1 PKID FROM [dbo].[TestTable111] ORDER BY PKID DESC"); + Console.WriteLine("lastId:{0}", lastId); - Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); + conn.Execute("Delete from TestTable111 where PKID > @pkid", new { pkid = 888 }); - Console.WriteLine(conn.Fetch("select top 1 * from TestTable111")?.Token); + Console.WriteLine("Current data count:{0}", conn.ExecuteScalarTo("SELECT COUNT(1) FROM [dbo].[TestTable111]")); - foreach (var entity in conn.Select("select * from TestTable111")) - { - Console.WriteLine(entity.Token); - } + Console.WriteLine(conn.Fetch("select top 1 * from TestTable111")?.Token); - Clean(conn); + foreach (var entity in conn.Select("select * from TestTable111")) + { + Console.WriteLine(entity.Token); } + + Clean(conn); } private static void Clean(DbConnection conn) diff --git a/samples/DotNetCoreSample/LoggerTest.cs b/samples/DotNetCoreSample/LoggerTest.cs index 74e94010..ffa7fa4e 100644 --- a/samples/DotNetCoreSample/LoggerTest.cs +++ b/samples/DotNetCoreSample/LoggerTest.cs @@ -55,14 +55,9 @@ public static void MicrosoftLoggingTest() .Test(); } - private class GenericTest + private class GenericTest(ILogger> logger) { - private readonly ILogger> _logger; - - public GenericTest(ILogger> logger) - { - _logger = logger; - } + private readonly ILogger> _logger = logger; public void Test() => _logger.LogInformation("test"); } diff --git a/samples/DotNetCoreSample/NewtonJsonFormatter.cs b/samples/DotNetCoreSample/NewtonJsonFormatter.cs index 685f1455..283f0011 100644 --- a/samples/DotNetCoreSample/NewtonJsonFormatter.cs +++ b/samples/DotNetCoreSample/NewtonJsonFormatter.cs @@ -15,16 +15,11 @@ public sealed class NewtonJsonFormatterOptions : ConsoleFormatterOptions { } -public sealed class NewtonJsonFormatter : ConsoleFormatter +public sealed class NewtonJsonFormatter(IOptions options) : ConsoleFormatter(FormatterName) { public const string FormatterName = "NewtonJson"; - private readonly NewtonJsonFormatterOptions _options; - - public NewtonJsonFormatter(IOptions options) : base(FormatterName) - { - _options = options.Value; - } + private readonly NewtonJsonFormatterOptions _options = options.Value; public override void Write(in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) { diff --git a/samples/DotNetCoreSample/ProcessExecutorTest.cs b/samples/DotNetCoreSample/ProcessExecutorTest.cs index b5de2401..dd8fdfe9 100644 --- a/samples/DotNetCoreSample/ProcessExecutorTest.cs +++ b/samples/DotNetCoreSample/ProcessExecutorTest.cs @@ -7,33 +7,31 @@ public class ProcessExecutorTest { public static void RawProcessTest() { - using (var process = new Process() + using var process = new Process() { StartInfo = new ProcessStartInfo("dotnet", "--info"), EnableRaisingEvents = true, - }) - { - process.StartInfo.UseShellExecute = false; - process.StartInfo.RedirectStandardOutput = true; - process.StartInfo.RedirectStandardInput = true; - process.StartInfo.RedirectStandardError = true; + }; + process.StartInfo.UseShellExecute = false; + process.StartInfo.RedirectStandardOutput = true; + process.StartInfo.RedirectStandardInput = true; + process.StartInfo.RedirectStandardError = true; - process.OutputDataReceived += (sender, args) => - { - Console.WriteLine(args.Data); - }; - process.Exited += (sender, args) => + process.OutputDataReceived += (sender, args) => + { + Console.WriteLine(args.Data); + }; + process.Exited += (sender, args) => + { + if (sender is Process _process) { - if (sender is Process _process) - { - Console.WriteLine($"The Process({_process.Id}) exited with code({_process.ExitCode})"); - } - }; - process.Start(); - process.BeginOutputReadLine(); + Console.WriteLine($"The Process({_process.Id}) exited with code({_process.ExitCode})"); + } + }; + process.Start(); + process.BeginOutputReadLine(); - process.WaitForExit(); - } + process.WaitForExit(); } public static void DotNetInfoTest() @@ -60,7 +58,7 @@ public static void DotNetNugetGlobalPackagesInfoTest() if (str.StartsWith("global-packages:")) { - folder = str.Substring("global-packages:".Length).Trim(); + folder = str["global-packages:".Length..].Trim(); } }; executor.Execute(); diff --git a/samples/DotNetCoreSample/Program.cs b/samples/DotNetCoreSample/Program.cs index 6f2f0867..bda532d9 100644 --- a/samples/DotNetCoreSample/Program.cs +++ b/samples/DotNetCoreSample/Program.cs @@ -312,7 +312,7 @@ //TotpTest.MainTest(); // exit test -// var exitToken = InvokeHelper.GetExitToken(); +// var exitToken = ApplicationHelper.ExitToken; // exitToken.Register(() => // { // Console.WriteLine(@"Exiting"); @@ -337,6 +337,16 @@ // GC.Collect(); // GC.WaitForPendingFinalizers(); +// await CommandExecutor.ExecuteCommandAndOutputAsync( +// "dotnet build \"C:\\projects\\sources\\dotnet-exec\\src\\dotnet-exec\\dotnet-exec.csproj\""); + +{ + var cts = CancellationTokenSource.CreateLinkedTokenSource(ApplicationHelper.ExitToken, default); + var registration = cts.Token.Register(() => Console.WriteLine(@"Exited")); + cts.Dispose(); + // registration would be disposed when cts dispose +} + await InvokeHelper.TryInvokeAsync(TemplatingSample.MainTest); ConsoleHelper.ReadKeyWithPrompt("Press any key to exit"); diff --git a/samples/DotNetCoreSample/RepositoryTest.cs b/samples/DotNetCoreSample/RepositoryTest.cs index b30bcf1c..d94bfeaa 100644 --- a/samples/DotNetCoreSample/RepositoryTest.cs +++ b/samples/DotNetCoreSample/RepositoryTest.cs @@ -60,14 +60,9 @@ public DbConnectionPool(IPooledObjectPolicy policy, int maximumRet } } - public class DbConnectionPoolPolicy : IPooledObjectPolicy + public class DbConnectionPoolPolicy(string connString) : IPooledObjectPolicy { - private readonly string _connString; - - public DbConnectionPoolPolicy(string connString) - { - _connString = connString; - } + private readonly string _connString = connString; public DbConnection Create() { diff --git a/samples/DotNetCoreSample/RequestHelperTest.cs b/samples/DotNetCoreSample/RequestHelperTest.cs index 5cdd6a75..f88867ea 100644 --- a/samples/DotNetCoreSample/RequestHelperTest.cs +++ b/samples/DotNetCoreSample/RequestHelperTest.cs @@ -23,7 +23,7 @@ public static void GetRequestParamTest() Debug.Assert(param.HasKeys()); param = GetParamInfo("https://www.baidu.com/?tn="); - Debug.Assert(param["tn"] == String.Empty); + Debug.Assert(param["tn"] == string.Empty); } private static NameValueCollection GetParamInfo(string url) diff --git a/samples/DotNetCoreSample/ServiceDecoratorTest.cs b/samples/DotNetCoreSample/ServiceDecoratorTest.cs index 161590d6..6e6a234a 100644 --- a/samples/DotNetCoreSample/ServiceDecoratorTest.cs +++ b/samples/DotNetCoreSample/ServiceDecoratorTest.cs @@ -34,13 +34,9 @@ public void Execute() } } - private sealed class JobDecorator : IJob + private sealed class JobDecorator(IJob job) : IJob { - private readonly IJob _job; - public JobDecorator(IJob job) - { - _job = job; - } + private readonly IJob _job = job; public string Name => $"??? {_job.Name}"; diff --git a/samples/DotNetCoreSample/TemplatingSample.cs b/samples/DotNetCoreSample/TemplatingSample.cs index 56b327e5..b8bad829 100644 --- a/samples/DotNetCoreSample/TemplatingSample.cs +++ b/samples/DotNetCoreSample/TemplatingSample.cs @@ -7,7 +7,7 @@ namespace DotNetCoreSample; -public class TemplatingSample +public static class TemplatingSample { public static async Task MainTest() { @@ -37,7 +37,7 @@ public static async Task MainTest() .AddInMemoryCollection([new("UserName1", "Test1234")]) .Build(); services.AddSingleton(configuration); - services.AddTemplating(); + services.AddTemplateEngine(); await using var provider = services.BuildServiceProvider(); var result = await provider.GetRequiredService() .RenderAsync("Hello {{$config UserName1}}"); diff --git a/samples/DotNetCoreSample/TotpTest.cs b/samples/DotNetCoreSample/TotpTest.cs index 44cb00f9..69cc4de6 100644 --- a/samples/DotNetCoreSample/TotpTest.cs +++ b/samples/DotNetCoreSample/TotpTest.cs @@ -14,8 +14,8 @@ public static void MainTest() var totp = new Totp(); while (true) { - var code = totp.ComputeWithTtl(Base32EncodeHelper.GetBytes(secret)); - Console.WriteLine(@$"{code.Code} {code.Ttl}"); + var (Code, Ttl) = totp.ComputeWithTtl(Base32EncodeHelper.GetBytes(secret)); + Console.WriteLine(@$"{Code} {Ttl}"); ConsoleHelper.ReadLineWithPrompt(); } } diff --git a/src/WeihanLi.Common.Logging.Serilog/SerilogLogHelperProvider.cs b/src/WeihanLi.Common.Logging.Serilog/SerilogLogHelperProvider.cs index dff45f39..12cf889f 100644 --- a/src/WeihanLi.Common.Logging.Serilog/SerilogLogHelperProvider.cs +++ b/src/WeihanLi.Common.Logging.Serilog/SerilogLogHelperProvider.cs @@ -7,7 +7,7 @@ namespace WeihanLi.Common.Logging.Serilog; internal sealed class SerilogLogHelperProvider : ILogHelperProvider, IDisposable { - private static readonly MessageTemplateParser _messageTemplateParser = new MessageTemplateParser(); + private static readonly MessageTemplateParser _messageTemplateParser = new(); public SerilogLogHelperProvider(LoggerConfiguration configuration) { @@ -46,37 +46,20 @@ public void Log(LogHelperLoggingEvent loggingEvent) } } - private LogEventLevel GetSerilogEventLevel(LogHelperLogLevel logHelperLevel) + private static LogEventLevel GetSerilogEventLevel(LogHelperLogLevel logHelperLevel) { - switch (logHelperLevel) + return logHelperLevel switch { - case LogHelperLogLevel.All: - return LogEventLevel.Verbose; - - case LogHelperLogLevel.Debug: - return LogEventLevel.Debug; - - case LogHelperLogLevel.Info: - return LogEventLevel.Information; - - case LogHelperLogLevel.Trace: - return LogEventLevel.Debug; - - case LogHelperLogLevel.Warn: - return LogEventLevel.Warning; - - case LogHelperLogLevel.Error: - return LogEventLevel.Error; - - case LogHelperLogLevel.Fatal: - return LogEventLevel.Fatal; - - case LogHelperLogLevel.None: - return LogEventLevel.Fatal; - - default: - return LogEventLevel.Warning; - } + LogHelperLogLevel.All => LogEventLevel.Verbose, + LogHelperLogLevel.Debug => LogEventLevel.Debug, + LogHelperLogLevel.Info => LogEventLevel.Information, + LogHelperLogLevel.Trace => LogEventLevel.Debug, + LogHelperLogLevel.Warn => LogEventLevel.Warning, + LogHelperLogLevel.Error => LogEventLevel.Error, + LogHelperLogLevel.Fatal => LogEventLevel.Fatal, + LogHelperLogLevel.None => LogEventLevel.Fatal, + _ => LogEventLevel.Warning, + }; } private const string SourceContextPropName = "SourceContext"; diff --git a/src/WeihanLi.Common.Logging.Serilog/SerilogLogger.cs b/src/WeihanLi.Common.Logging.Serilog/SerilogLogger.cs index 4fa68574..bbe2293e 100644 --- a/src/WeihanLi.Common.Logging.Serilog/SerilogLogger.cs +++ b/src/WeihanLi.Common.Logging.Serilog/SerilogLogger.cs @@ -16,7 +16,7 @@ internal sealed class SerilogLogger : FrameworkLogger private readonly SerilogLoggerProvider _provider; private readonly ILogger _logger; - private static readonly MessageTemplateParser _messageTemplateParser = new MessageTemplateParser(); + private static readonly MessageTemplateParser _messageTemplateParser = new(); public SerilogLogger( SerilogLoggerProvider provider, @@ -67,7 +67,7 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except } else if (property.Key.StartsWith("@")) { - if (logger.BindProperty(property.Key.Substring(1), property.Value, true, out var destructured)) + if (logger.BindProperty(property.Key[1..], property.Value, true, out var destructured)) properties.Add(destructured); } else @@ -127,27 +127,16 @@ public void Log(LogLevel logLevel, EventId eventId, TState state, Except private static LogEventLevel ConvertLevel(LogLevel logLevel) { - switch (logLevel) + return logLevel switch { - case LogLevel.Critical: - return LogEventLevel.Fatal; - - case LogLevel.Error: - return LogEventLevel.Error; - - case LogLevel.Warning: - return LogEventLevel.Warning; - - case LogLevel.Information: - return LogEventLevel.Information; - - case LogLevel.Debug: - return LogEventLevel.Debug; + LogLevel.Critical => LogEventLevel.Fatal, + LogLevel.Error => LogEventLevel.Error, + LogLevel.Warning => LogEventLevel.Warning, + LogLevel.Information => LogEventLevel.Information, + LogLevel.Debug => LogEventLevel.Debug, // ReSharper disable once RedundantCaseLabel - case LogLevel.Trace: - default: - return LogEventLevel.Verbose; - } + _ => LogEventLevel.Verbose, + }; } private static LogEventProperty CreateEventIdProperty(EventId eventId) diff --git a/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerProvider.cs b/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerProvider.cs index 0b54f20b..dd39f5a3 100644 --- a/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerProvider.cs +++ b/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerProvider.cs @@ -71,7 +71,7 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) if (scopeItem != null) { - scopeItems ??= new List(); + scopeItems ??= []; scopeItems.Add(scopeItem); } } @@ -83,7 +83,7 @@ public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) } } - private readonly AsyncLocal _value = new AsyncLocal(); + private readonly AsyncLocal _value = new(); internal SerilogLoggerScope? CurrentScope { diff --git a/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerScope.cs b/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerScope.cs index 5cc98146..2d71d4e7 100644 --- a/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerScope.cs +++ b/src/WeihanLi.Common.Logging.Serilog/SerilogLoggerScope.cs @@ -73,7 +73,7 @@ public void EnrichAndCreateScopeItem(LogEvent logEvent, ILogEventPropertyFactory if (key.StartsWith("@")) { - key = key.Substring(1); + key = key[1..]; destructureObject = true; } diff --git a/src/WeihanLi.Common/Aspect/AspectInvokeException.cs b/src/WeihanLi.Common/Aspect/AspectInvokeException.cs index bd8617ed..3f6ed0b7 100644 --- a/src/WeihanLi.Common/Aspect/AspectInvokeException.cs +++ b/src/WeihanLi.Common/Aspect/AspectInvokeException.cs @@ -1,11 +1,6 @@ namespace WeihanLi.Common.Aspect; -public sealed class AspectInvokeException : Exception +public sealed class AspectInvokeException(IInvocation invocation, Exception innerException) : Exception($"Invoke {invocation.ProxyMethod.Name} exception", innerException) { - public IInvocation Invocation { get; } - - public AspectInvokeException(IInvocation invocation, Exception innerException) : base($"Invoke {invocation.ProxyMethod.Name} exception", innerException) - { - Invocation = invocation; - } + public IInvocation Invocation { get; } = invocation; } diff --git a/src/WeihanLi.Common/Aspect/DefaultProxyFactory.cs b/src/WeihanLi.Common/Aspect/DefaultProxyFactory.cs index bc47d62d..11127b31 100644 --- a/src/WeihanLi.Common/Aspect/DefaultProxyFactory.cs +++ b/src/WeihanLi.Common/Aspect/DefaultProxyFactory.cs @@ -3,18 +3,13 @@ namespace WeihanLi.Common.Aspect; -public sealed class DefaultProxyFactory : IProxyFactory +public sealed class DefaultProxyFactory + (IProxyTypeFactory proxyTypeFactory, IServiceProvider? serviceProvider = null) : IProxyFactory { public static readonly IProxyFactory Instance = new DefaultProxyFactory(DefaultProxyTypeFactory.Instance); - private readonly IProxyTypeFactory _proxyTypeFactory; - private readonly IServiceProvider _serviceProvider; - - public DefaultProxyFactory(IProxyTypeFactory proxyTypeFactory, IServiceProvider? serviceProvider = null) - { - _proxyTypeFactory = proxyTypeFactory; - _serviceProvider = serviceProvider ?? DependencyResolver.Current; - } + private readonly IProxyTypeFactory _proxyTypeFactory = proxyTypeFactory; + private readonly IServiceProvider _serviceProvider = serviceProvider ?? DependencyResolver.Current; [RequiresDynamicCode("Defining a dynamic assembly requires dynamic code.")] [RequiresUnreferencedCode("Unreferenced code may be used")] diff --git a/src/WeihanLi.Common/Aspect/DelegateInterceptor.cs b/src/WeihanLi.Common/Aspect/DelegateInterceptor.cs index 75003cac..641a6eac 100644 --- a/src/WeihanLi.Common/Aspect/DelegateInterceptor.cs +++ b/src/WeihanLi.Common/Aspect/DelegateInterceptor.cs @@ -1,14 +1,9 @@ namespace WeihanLi.Common.Aspect; [CLSCompliant(false)] -public sealed class DelegateInterceptor : AbstractInterceptor +public sealed class DelegateInterceptor(Func, Task> interceptFunc) : AbstractInterceptor { - private readonly Func, Task> _interceptFunc; - - public DelegateInterceptor(Func, Task> interceptFunc) - { - _interceptFunc = interceptFunc ?? throw new ArgumentNullException(nameof(interceptFunc)); - } + private readonly Func, Task> _interceptFunc = Guard.NotNull(interceptFunc); public override Task Invoke(IInvocation invocation, Func next) { diff --git a/src/WeihanLi.Common/Aspect/FluentAspectOptions.cs b/src/WeihanLi.Common/Aspect/FluentAspectOptions.cs index 06207968..1b0402cb 100644 --- a/src/WeihanLi.Common/Aspect/FluentAspectOptions.cs +++ b/src/WeihanLi.Common/Aspect/FluentAspectOptions.cs @@ -2,18 +2,18 @@ public sealed class FluentAspectOptions { - public readonly Dictionary, IInterceptionConfiguration> InterceptionConfigurations = new(); + public readonly Dictionary, IInterceptionConfiguration> InterceptionConfigurations = []; private IInterceptorResolver _interceptorResolver = FluentConfigInterceptorResolver.Instance; - public HashSet> NoInterceptionConfigurations { get; } = new(); + public HashSet> NoInterceptionConfigurations { get; } = []; public IInterceptorResolver InterceptorResolver { get => _interceptorResolver; - set => _interceptorResolver = value ?? throw new ArgumentNullException(nameof(value)); + set => _interceptorResolver = Guard.NotNull(value); } - public HashSet Enrichers { get; } = new(); + public HashSet Enrichers { get; } = []; public IProxyFactory ProxyFactory { get; set; } = DefaultProxyFactory.Instance; } diff --git a/src/WeihanLi.Common/Aspect/FluentAspectOptionsExtensions.cs b/src/WeihanLi.Common/Aspect/FluentAspectOptionsExtensions.cs index 010e4927..93e484ac 100644 --- a/src/WeihanLi.Common/Aspect/FluentAspectOptionsExtensions.cs +++ b/src/WeihanLi.Common/Aspect/FluentAspectOptionsExtensions.cs @@ -46,10 +46,7 @@ public static IInterceptionConfiguration InterceptMethod(this FluentAspectOpt public static IInterceptionConfiguration InterceptMethod(this FluentAspectOptions options, MethodInfo method) { - if (null == method) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); var methodSignature = method.GetSignature(); return options.InterceptMethod(m => m.GetSignature().Equals(methodSignature)); @@ -58,10 +55,7 @@ public static IInterceptionConfiguration InterceptMethod(this FluentAspectOpt public static IInterceptionConfiguration InterceptMethod(this FluentAspectOptions options, MethodInfo method) { - if (null == method) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); var methodSignature = method.GetSignature(); return options.InterceptMethod(m => m.GetSignature().Equals(methodSignature)); @@ -213,10 +207,7 @@ public static FluentAspectOptions NoInterceptMethod(this FluentAspectOptions opt public static FluentAspectOptions NoInterceptMethod(this FluentAspectOptions options, MethodInfo method) { - if (null == method) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); var methodSignature = method.GetSignature(); return options.NoInterceptMethod(m => m.GetSignature().Equals(methodSignature)); @@ -225,10 +216,7 @@ public static FluentAspectOptions NoInterceptMethod(this FluentAspectOptions public static FluentAspectOptions NoInterceptMethod(this FluentAspectOptions options, MethodInfo method) { - if (null == method) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); var methodSignature = method.GetSignature(); return options.NoInterceptMethod(m => m.GetSignature().Equals(methodSignature)); diff --git a/src/WeihanLi.Common/Aspect/FluentAspectsBuilder.cs b/src/WeihanLi.Common/Aspect/FluentAspectsBuilder.cs index d586d4f7..ab269008 100644 --- a/src/WeihanLi.Common/Aspect/FluentAspectsBuilder.cs +++ b/src/WeihanLi.Common/Aspect/FluentAspectsBuilder.cs @@ -7,12 +7,7 @@ public interface IFluentAspectsBuilder IServiceCollection Services { get; } } -internal sealed class FluentAspectsBuilder : IFluentAspectsBuilder +internal sealed class FluentAspectsBuilder(IServiceCollection serviceCollection) : IFluentAspectsBuilder { - public FluentAspectsBuilder(IServiceCollection serviceCollection) - { - Services = serviceCollection; - } - - public IServiceCollection Services { get; } + public IServiceCollection Services { get; } = serviceCollection; } diff --git a/src/WeihanLi.Common/Aspect/FluentAspectsServiceContainerBuilder.cs b/src/WeihanLi.Common/Aspect/FluentAspectsServiceContainerBuilder.cs index 5b57f72f..da30a5bd 100644 --- a/src/WeihanLi.Common/Aspect/FluentAspectsServiceContainerBuilder.cs +++ b/src/WeihanLi.Common/Aspect/FluentAspectsServiceContainerBuilder.cs @@ -7,12 +7,7 @@ public interface IFluentAspectsServiceContainerBuilder IServiceContainerBuilder Services { get; } } -internal sealed class FluentAspectsServiceContainerBuilder : IFluentAspectsServiceContainerBuilder +internal sealed class FluentAspectsServiceContainerBuilder(IServiceContainerBuilder serviceCollection) : IFluentAspectsServiceContainerBuilder { - public FluentAspectsServiceContainerBuilder(IServiceContainerBuilder serviceCollection) - { - Services = serviceCollection; - } - - public IServiceContainerBuilder Services { get; } + public IServiceContainerBuilder Services { get; } = serviceCollection; } diff --git a/src/WeihanLi.Common/Aspect/IInvocation.cs b/src/WeihanLi.Common/Aspect/IInvocation.cs index 4053236b..24457b2c 100644 --- a/src/WeihanLi.Common/Aspect/IInvocation.cs +++ b/src/WeihanLi.Common/Aspect/IInvocation.cs @@ -53,7 +53,7 @@ public AspectInvocation( ProxyTarget = proxyTarget; Target = target; Arguments = arguments; - GenericArguments = methodBase?.GetGenericArguments() ?? Array.Empty(); + GenericArguments = methodBase?.GetGenericArguments() ?? []; if (proxyMethod.ContainsGenericParameters && GenericArguments.Length > 0) { @@ -64,6 +64,6 @@ public AspectInvocation( ProxyMethod = proxyMethod; } - Properties = new Dictionary(); + Properties = []; } } diff --git a/src/WeihanLi.Common/Aspect/InvocationEnricherExtensions.cs b/src/WeihanLi.Common/Aspect/InvocationEnricherExtensions.cs index b1f1cb43..e8810f0b 100644 --- a/src/WeihanLi.Common/Aspect/InvocationEnricherExtensions.cs +++ b/src/WeihanLi.Common/Aspect/InvocationEnricherExtensions.cs @@ -5,10 +5,7 @@ public static class InvocationEnricherExtensions public static void AddProperty(this IInvocation invocation, string propertyName, object propertyValue, bool overwrite = false) { - if (null == invocation) - { - throw new ArgumentNullException(nameof(invocation)); - } + Guard.NotNull(invocation); if (!invocation.Properties.ContainsKey(propertyName) || overwrite) { @@ -19,10 +16,7 @@ public static void AddProperty(this IInvocation invocation, string propertyName, public static void AddProperty(this IInvocation invocation, string propertyName, Func propertyValueFactory, bool overwrite = false) { - if (null == invocation) - { - throw new ArgumentNullException(nameof(invocation)); - } + Guard.NotNull(invocation); if (!invocation.Properties.ContainsKey(propertyName) || overwrite) diff --git a/src/WeihanLi.Common/Aspect/MethodSignature.cs b/src/WeihanLi.Common/Aspect/MethodSignature.cs index 816610d8..429329f9 100644 --- a/src/WeihanLi.Common/Aspect/MethodSignature.cs +++ b/src/WeihanLi.Common/Aspect/MethodSignature.cs @@ -2,21 +2,15 @@ namespace WeihanLi.Common.Aspect; -internal sealed class MethodSignature +internal sealed class MethodSignature(string methodName, IReadOnlyList parameters) { - public IReadOnlyList Parameters { get; } - public string MethodName { get; } + public IReadOnlyList Parameters { get; } = parameters; + public string MethodName { get; } = methodName; public MethodSignature(MethodBase method) : this(method.Name, method.GetParameters().Select(p => p.ParameterType).ToArray()) { } - public MethodSignature(string methodName, IReadOnlyList parameters) - { - Parameters = parameters; - MethodName = methodName; - } - public override bool Equals(object? obj) { // if object is null or type does not match return false... diff --git a/src/WeihanLi.Common/Aspect/ProxyFactoryExtensions.cs b/src/WeihanLi.Common/Aspect/ProxyFactoryExtensions.cs index dcefe794..9a77cc23 100644 --- a/src/WeihanLi.Common/Aspect/ProxyFactoryExtensions.cs +++ b/src/WeihanLi.Common/Aspect/ProxyFactoryExtensions.cs @@ -111,7 +111,7 @@ public static TService CreateProxyWithTarget(this IProxyFactory proxyF public static object CreateProxyWithTarget(this IProxyFactory proxyFactory, Type serviceType, object target) { - return proxyFactory.CreateProxyWithTarget(serviceType, target, Array.Empty()); + return proxyFactory.CreateProxyWithTarget(serviceType, target, []); } #endregion CreateProxyWithTarget diff --git a/src/WeihanLi.Common/Aspect/ProxyUtils.cs b/src/WeihanLi.Common/Aspect/ProxyUtils.cs index 67d9dd2e..8c9d0e5a 100644 --- a/src/WeihanLi.Common/Aspect/ProxyUtils.cs +++ b/src/WeihanLi.Common/Aspect/ProxyUtils.cs @@ -14,21 +14,21 @@ internal static class ProxyUtils private const MethodAttributes InterfaceMethodAttributes = MethodAttributes.Public | MethodAttributes.Final | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual; private static readonly ModuleBuilder _moduleBuilder; - private static readonly Dictionary _proxyTypes = new(); + private static readonly Dictionary _proxyTypes = []; private const string TargetFieldName = "__target"; private static readonly object _typeLock = new(); private static readonly Func _proxyTypeNameResolver; - private static readonly HashSet _ignoredMethods = new() - { + private static readonly HashSet _ignoredMethods = + [ "ToString", "GetHashCode", "Equals", "GetType", "Finalize", - }; + ]; static ProxyUtils() { @@ -96,7 +96,7 @@ public static Type CreateInterfaceProxy(Type interfaceType) return proxyType; } - var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(object), new[] { interfaceType }); + var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, typeof(object), [interfaceType]); GenericParameterUtils.DefineGenericParameter(interfaceType, typeBuilder); @@ -217,7 +217,7 @@ public static Type CreateInterfaceProxy(Type interfaceType, Type? implementType) { return proxyType; } - var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, null, new[] { interfaceType }); + var typeBuilder = _moduleBuilder.DefineType(proxyTypeName, TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed, null, [interfaceType]); GenericParameterUtils.DefineGenericParameter(interfaceType, typeBuilder); var targetField = typeBuilder.DefineField(TargetFieldName, implementType, FieldAttributes.Private); @@ -316,10 +316,7 @@ public static Type CreateClassProxy(Type serviceType, Type? implementType) { Guard.NotNull(serviceType); - if (implementType is null) - { - implementType = serviceType; - } + implementType ??= serviceType; if (serviceType.IsSealed || implementType.IsSealed) { throw new InvalidOperationException("the class type is sealed"); diff --git a/src/WeihanLi.Common/Aspect/ServiceCollectionExtensions.cs b/src/WeihanLi.Common/Aspect/ServiceCollectionExtensions.cs index d06707d0..261e1182 100644 --- a/src/WeihanLi.Common/Aspect/ServiceCollectionExtensions.cs +++ b/src/WeihanLi.Common/Aspect/ServiceCollectionExtensions.cs @@ -9,22 +9,15 @@ public static class ServiceCollectionExtensions { public static IFluentAspectsBuilder AddFluentAspects(this IServiceCollection serviceCollection, Action optionsAction) { - if (null == serviceCollection) - { - throw new ArgumentNullException(nameof(serviceCollection)); - } - if (null == optionsAction) - { - throw new ArgumentNullException(nameof(optionsAction)); - } + Guard.NotNull(serviceCollection); + Guard.NotNull(optionsAction); FluentAspects.Configure(optionsAction); return AddFluentAspects(serviceCollection); } public static IFluentAspectsBuilder AddFluentAspects(this IServiceCollection serviceCollection) { - if (null == serviceCollection) - throw new ArgumentNullException(nameof(serviceCollection)); + Guard.NotNull(serviceCollection); serviceCollection.TryAddTransient(); serviceCollection.TryAddTransient(); diff --git a/src/WeihanLi.Common/Aspect/ServiceContainerBuilderExtensions.cs b/src/WeihanLi.Common/Aspect/ServiceContainerBuilderExtensions.cs index 8ac5b2e9..c23288d9 100644 --- a/src/WeihanLi.Common/Aspect/ServiceContainerBuilderExtensions.cs +++ b/src/WeihanLi.Common/Aspect/ServiceContainerBuilderExtensions.cs @@ -9,22 +9,15 @@ public static class ServiceContainerBuilderExtensions { public static IFluentAspectsServiceContainerBuilder AddFluentAspects(this IServiceContainerBuilder serviceCollection, Action optionsAction) { - if (null == serviceCollection) - { - throw new ArgumentNullException(nameof(serviceCollection)); - } - if (null == optionsAction) - { - throw new ArgumentNullException(nameof(optionsAction)); - } + Guard.NotNull(serviceCollection); + Guard.NotNull(optionsAction); FluentAspects.Configure(optionsAction); return AddFluentAspects(serviceCollection); } public static IFluentAspectsServiceContainerBuilder AddFluentAspects(this IServiceContainerBuilder serviceCollection) { - if (null == serviceCollection) - throw new ArgumentNullException(nameof(serviceCollection)); + Guard.NotNull(serviceCollection); serviceCollection.AddTransient(); serviceCollection.AddTransient(); @@ -37,6 +30,8 @@ public static IServiceContainerBuilder AddProxyService(thi where TImplement : TService where TService : class { + Guard.NotNull(serviceCollection); + serviceCollection.Add(new ServiceDefinition(typeof(TService), sp => { var proxyFactory = sp.ResolveRequiredService(); @@ -49,6 +44,7 @@ public static IServiceContainerBuilder AddSingletonProxy(t where TImplement : TService where TService : class { + Guard.NotNull(serviceCollection); return serviceCollection.AddProxyService(ServiceLifetime.Singleton); } @@ -56,6 +52,7 @@ public static IServiceContainerBuilder AddScopedProxy(this where TImplement : TService where TService : class { + Guard.NotNull(serviceCollection); return serviceCollection.AddProxyService(ServiceLifetime.Scoped); } @@ -63,12 +60,14 @@ public static IServiceContainerBuilder AddTransientProxy(t where TImplement : TService where TService : class { + Guard.NotNull(serviceCollection); return serviceCollection.AddProxyService(ServiceLifetime.Transient); } public static IServiceContainerBuilder AddProxyService(this IServiceContainerBuilder serviceCollection, ServiceLifetime serviceLifetime) where TService : class { + Guard.NotNull(serviceCollection); serviceCollection.Add(new ServiceDefinition(typeof(TService), sp => { var proxyFactory = sp.ResolveRequiredService(); @@ -95,6 +94,7 @@ public static IServiceContainer BuildFluentAspectsContainer(this IServiceContain Action? aspectBuildAction = null, Expression>? ignoreTypesFilter = null) { + Guard.NotNull(serviceCollection); var services = new ServiceContainerBuilder(); var aspectBuilder = null != optionsAction diff --git a/src/WeihanLi.Common/Data/Expressions/DateTimeExpressionParser.cs b/src/WeihanLi.Common/Data/Expressions/DateTimeExpressionParser.cs index a927aa7e..90ab8558 100644 --- a/src/WeihanLi.Common/Data/Expressions/DateTimeExpressionParser.cs +++ b/src/WeihanLi.Common/Data/Expressions/DateTimeExpressionParser.cs @@ -10,18 +10,13 @@ internal static partial class SqlExpressionParser { public static string ParseDateTimeMemberAccess(MemberExpression exp, IDictionary? columnMappings) { - switch (exp.Member.Name) + return exp.Member.Name switch { - case "Now": - return $"GETDATE()"; - - case "UtcNow": - return $"GETUTCDATE()"; - - case "Today": - return "CONVERT(CHAR(10), GETDATE(),120)"; - } - return string.Empty; + "Now" => $"GETDATE()", + "UtcNow" => $"GETUTCDATE()", + "Today" => "CONVERT(CHAR(10), GETDATE(),120)", + _ => string.Empty, + }; } public static string ParseDateTimeMethodCall(MethodCallExpression exp, IDictionary? columnMappings) diff --git a/src/WeihanLi.Common/Data/Expressions/StringExpressionParser.cs b/src/WeihanLi.Common/Data/Expressions/StringExpressionParser.cs index ba5ec974..fbf9aef8 100644 --- a/src/WeihanLi.Common/Data/Expressions/StringExpressionParser.cs +++ b/src/WeihanLi.Common/Data/Expressions/StringExpressionParser.cs @@ -10,15 +10,12 @@ internal static partial class SqlExpressionParser { public static string ParseStringMemberAccess(MemberExpression exp, IDictionary? columnMappings) { - switch (exp.Member.Name) + return exp.Member.Name switch { - case "Empty": - return string.Empty; - - case "Length": - return $"LEN({ParseExpression(exp.Expression, columnMappings)})"; - } - throw new NotImplementedException(); + "Empty" => string.Empty, + "Length" => $"LEN({ParseExpression(exp.Expression, columnMappings)})", + _ => throw new NotImplementedException(), + }; } public static string ParseStringMethodCall(MethodCallExpression exp, IDictionary? columnMappings) diff --git a/src/WeihanLi.Common/Data/Repository.cs b/src/WeihanLi.Common/Data/Repository.cs index 734e6abe..5e5b2a70 100644 --- a/src/WeihanLi.Common/Data/Repository.cs +++ b/src/WeihanLi.Common/Data/Repository.cs @@ -11,7 +11,7 @@ namespace WeihanLi.Common.Data; [CLSCompliant(false)] -public class Repository<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] TEntity> : IRepository where TEntity : new() +public class Repository<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] TEntity>(Func dbConnectionFunc) : IRepository where TEntity : new() { #region TODO: Cache External @@ -50,12 +50,7 @@ namespace WeihanLi.Common.Data; #endregion TODO: Cache External - protected readonly Lazy _dbConnection; - - public Repository(Func dbConnectionFunc) - { - _dbConnection = new Lazy(dbConnectionFunc, true); - } + protected readonly Lazy _dbConnection = new(dbConnectionFunc, true); public virtual int Count(Expression> whereExpression) { @@ -553,7 +548,7 @@ public virtual int UpdateWithout(TEntity entity, params string[]? propertyNames) return -1; } //... - var updateWithoutCols = propertyNames ?? Array.Empty(); + var updateWithoutCols = propertyNames ?? []; var updateCols = ColumnMappings.Keys .Where(c => !updateWithoutCols.Contains(c) && !keyEntries.ContainsKey(c)) .ToArray(); diff --git a/src/WeihanLi.Common/Data/SqlExpressionParser.cs b/src/WeihanLi.Common/Data/SqlExpressionParser.cs index d9e73b3f..1e987ab6 100644 --- a/src/WeihanLi.Common/Data/SqlExpressionParser.cs +++ b/src/WeihanLi.Common/Data/SqlExpressionParser.cs @@ -33,9 +33,7 @@ public static string ParseExpression(Expression? exp, IDictionary parameters) { - public string SqlText { get; } + public string SqlText { get; } = sqlText; - public IDictionary Parameters { get; } - - public SqlParseResult(string sqlText, IDictionary parameters) - { - SqlText = sqlText; - Parameters = parameters; - } + public IDictionary Parameters { get; } = parameters; } diff --git a/src/WeihanLi.Common/Data/SqlExpressionVisitor.cs b/src/WeihanLi.Common/Data/SqlExpressionVisitor.cs index 2edd3a74..a8e3aa37 100644 --- a/src/WeihanLi.Common/Data/SqlExpressionVisitor.cs +++ b/src/WeihanLi.Common/Data/SqlExpressionVisitor.cs @@ -3,15 +3,10 @@ namespace WeihanLi.Common.Data; -public class SqlExpressionVisitor : ExpressionVisitor +public class SqlExpressionVisitor(IDictionary? columnMappings) : ExpressionVisitor { private readonly Stack _leaves = new(); - private readonly IDictionary? _columnMappings; - - public SqlExpressionVisitor(IDictionary? columnMappings) - { - _columnMappings = columnMappings; - } + private readonly IDictionary? _columnMappings = columnMappings; public string GetCondition() => _leaves.StringJoin(" "); diff --git a/src/WeihanLi.Common/Data/UnitOfWork.cs b/src/WeihanLi.Common/Data/UnitOfWork.cs index c6dabfcb..8e9ecffc 100644 --- a/src/WeihanLi.Common/Data/UnitOfWork.cs +++ b/src/WeihanLi.Common/Data/UnitOfWork.cs @@ -12,17 +12,14 @@ public class UnitOfWork : IUnitOfWork, IDisposable public UnitOfWork(IDbConnection dbConnection) { - if (null == dbConnection) - { - throw new ArgumentNullException(nameof(dbConnection)); - } + Guard.NotNull(dbConnection); dbConnection.EnsureOpen(); _dbTransaction = dbConnection.BeginTransaction(); } public UnitOfWork(IDbTransaction dbTransaction) { - _dbTransaction = dbTransaction ?? throw new ArgumentNullException(nameof(dbTransaction)); + _dbTransaction = Guard.NotNull(dbTransaction); } public virtual void Commit() => _dbTransaction.Commit(); diff --git a/src/WeihanLi.Common/DependencyInjection/ServiceContainer.cs b/src/WeihanLi.Common/DependencyInjection/ServiceContainer.cs index 5cd999de..66b69912 100644 --- a/src/WeihanLi.Common/DependencyInjection/ServiceContainer.cs +++ b/src/WeihanLi.Common/DependencyInjection/ServiceContainer.cs @@ -19,19 +19,13 @@ internal sealed class ServiceContainer : IServiceContainer private readonly ConcurrentDictionary _singletonInstances; private readonly ConcurrentDictionary _scopedInstances = new(); - private readonly ConcurrentBag _transientDisposables = new(); + private readonly ConcurrentBag _transientDisposables = []; - private sealed class ServiceKey : IEquatable + private sealed class ServiceKey(Type serviceType, ServiceDefinition definition) : IEquatable { - public Type ServiceType { get; } + public Type ServiceType { get; } = serviceType; - public Type ImplementType { get; } - - public ServiceKey(Type serviceType, ServiceDefinition definition) - { - ServiceType = serviceType; - ImplementType = definition.GetImplementType(); - } + public Type ImplementType { get; } = definition.GetImplementType(); public bool Equals(ServiceKey? other) { @@ -208,13 +202,8 @@ public void Dispose() } return ctorInfo; - }); - if (ctor == null) - { - throw new InvalidOperationException( + }) ?? throw new InvalidOperationException( $"service {serviceType.FullName} does not have any public constructors"); - } - var parameters = ctor.GetParameters(); if (parameters.Length == 0) { @@ -347,7 +336,7 @@ public void Dispose() var toArrayMethod = typeof(Enumerable).GetMethod("ToArray", BindingFlags.Static | BindingFlags.Public) ?.MakeGenericMethod(innerServiceType); - return toArrayMethod?.Invoke(null, new[] { castValue }); + return toArrayMethod?.Invoke(null, [castValue]); } return list; } diff --git a/src/WeihanLi.Common/DependencyInjection/ServiceContainerBuilder.cs b/src/WeihanLi.Common/DependencyInjection/ServiceContainerBuilder.cs index fb0bf5c8..119348ef 100644 --- a/src/WeihanLi.Common/DependencyInjection/ServiceContainerBuilder.cs +++ b/src/WeihanLi.Common/DependencyInjection/ServiceContainerBuilder.cs @@ -13,7 +13,7 @@ public interface IServiceContainerBuilder : IEnumerable public sealed class ServiceContainerBuilder : IServiceContainerBuilder { - private readonly List _services = new(); + private readonly List _services = []; public IServiceContainerBuilder Add(ServiceDefinition item) { diff --git a/src/WeihanLi.Common/DependencyResolver.cs b/src/WeihanLi.Common/DependencyResolver.cs index 1acb744b..892b85db 100644 --- a/src/WeihanLi.Common/DependencyResolver.cs +++ b/src/WeihanLi.Common/DependencyResolver.cs @@ -48,14 +48,9 @@ public static void SetDependencyResolver(IServiceProvider serviceProvider) public static void SetDependencyResolver(IServiceCollection services) => SetDependencyResolver(new ServiceProviderDependencyResolver(services.BuildServiceProvider())); - private sealed class ServiceProviderDependencyResolver : IDependencyResolver + private sealed class ServiceProviderDependencyResolver(ServiceProvider serviceProvider) : IDependencyResolver { - private readonly ServiceProvider _serviceProvider; - - public ServiceProviderDependencyResolver(ServiceProvider serviceProvider) - { - _serviceProvider = serviceProvider; - } + private readonly ServiceProvider _serviceProvider = serviceProvider; public object? GetService(Type serviceType) { @@ -136,16 +131,10 @@ public async Task TryInvokeServiceAsync(Func? ac } } - private sealed class DelegateBasedDependencyResolver : IDependencyResolver + private sealed class DelegateBasedDependencyResolver(Func getService, Func> getServices) : IDependencyResolver { - private readonly Func _getService; - private readonly Func> _getServices; - - public DelegateBasedDependencyResolver(Func getService, Func> getServices) - { - _getService = Guard.NotNull(getService); - _getServices = Guard.NotNull(getServices); - } + private readonly Func _getService = Guard.NotNull(getService); + private readonly Func> _getServices = Guard.NotNull(getServices); public object? GetService(Type serviceType) => _getService(serviceType); @@ -176,14 +165,9 @@ public async Task TryInvokeServiceAsync(Func? ac } } - private sealed class ServiceContainerDependencyResolver : IDependencyResolver + private sealed class ServiceContainerDependencyResolver(IServiceContainer serviceContainer) : IDependencyResolver { - private readonly IServiceContainer _rootContainer; - - public ServiceContainerDependencyResolver(IServiceContainer serviceContainer) - { - _rootContainer = serviceContainer; - } + private readonly IServiceContainer _rootContainer = serviceContainer; public object? GetService(Type serviceType) { diff --git a/src/WeihanLi.Common/Event/DelegateEventHandler.cs b/src/WeihanLi.Common/Event/DelegateEventHandler.cs index 6eb9acfc..6981960d 100644 --- a/src/WeihanLi.Common/Event/DelegateEventHandler.cs +++ b/src/WeihanLi.Common/Event/DelegateEventHandler.cs @@ -19,14 +19,13 @@ public sealed class DelegateEventHandler : EventHandlerBase public DelegateEventHandler(Action action) { - if (null == action) throw new ArgumentNullException(nameof(action)); - + Guard.NotNull(action); _func = action.WrapTask(); } public DelegateEventHandler(Func func) { - _func = func ?? throw new ArgumentNullException(nameof(func)); + _func = Guard.NotNull(func); } public override Task Handle(TEvent @event) diff --git a/src/WeihanLi.Common/Event/EventBase.cs b/src/WeihanLi.Common/Event/EventBase.cs index e678221c..5fcfc146 100644 --- a/src/WeihanLi.Common/Event/EventBase.cs +++ b/src/WeihanLi.Common/Event/EventBase.cs @@ -61,21 +61,13 @@ public static class EventBaseExtensions public static string ToEventMsg(this TEvent @event) where TEvent : class, IEventBase { - if (null == @event) - { - throw new ArgumentNullException(nameof(@event)); - } - + Guard.NotNull(@event); return @event.ToJson(EventSerializerSettings); } public static IEventBase ToEvent(this string eventMsg) { - if (null == eventMsg) - { - throw new ArgumentNullException(nameof(eventMsg)); - } - + Guard.NotNull(eventMsg); return eventMsg.JsonToObject(EventSerializerSettings); } } diff --git a/src/WeihanLi.Common/Event/EventBus.cs b/src/WeihanLi.Common/Event/EventBus.cs index 2205dbc4..a0b93cff 100644 --- a/src/WeihanLi.Common/Event/EventBus.cs +++ b/src/WeihanLi.Common/Event/EventBus.cs @@ -9,18 +9,12 @@ namespace WeihanLi.Common.Event; /// /// EventBus in process /// -public sealed class EventBus : IEventBus +public sealed class EventBus(IEventSubscriptionManager subscriptionManager, IEventHandlerFactory eventHandlerFactory) : IEventBus { private static readonly ILogHelperLogger Logger = Helpers.LogHelper.GetLogger(); - private readonly IEventSubscriptionManager _subscriptionManager; - private readonly IEventHandlerFactory _eventHandlerFactory; - - public EventBus(IEventSubscriptionManager subscriptionManager, IEventHandlerFactory eventHandlerFactory) - { - _subscriptionManager = subscriptionManager; - _eventHandlerFactory = eventHandlerFactory; - } + private readonly IEventSubscriptionManager _subscriptionManager = subscriptionManager; + private readonly IEventHandlerFactory _eventHandlerFactory = eventHandlerFactory; public bool Publish(TEvent @event) where TEvent : class, IEventBase { diff --git a/src/WeihanLi.Common/Event/EventBusExtensions.cs b/src/WeihanLi.Common/Event/EventBusExtensions.cs index 85c4913b..e53197b7 100644 --- a/src/WeihanLi.Common/Event/EventBusExtensions.cs +++ b/src/WeihanLi.Common/Event/EventBusExtensions.cs @@ -13,14 +13,9 @@ public interface IEventBuilder IServiceCollection Services { get; } } -internal sealed class EventBuilder : IEventBuilder +internal sealed class EventBuilder(IServiceCollection services) : IEventBuilder { - public IServiceCollection Services { get; } - - public EventBuilder(IServiceCollection services) - { - Services = services; - } + public IServiceCollection Services { get; } = services; } public static class EventBusExtensions diff --git a/src/WeihanLi.Common/Event/EventHandlerFactory.cs b/src/WeihanLi.Common/Event/EventHandlerFactory.cs index 04726b3e..32ee872d 100644 --- a/src/WeihanLi.Common/Event/EventHandlerFactory.cs +++ b/src/WeihanLi.Common/Event/EventHandlerFactory.cs @@ -7,17 +7,11 @@ namespace WeihanLi.Common.Event; -public sealed class DefaultEventHandlerFactory : IEventHandlerFactory +public sealed class DefaultEventHandlerFactory(IEventSubscriptionManager subscriptionManager, IServiceProvider serviceProvider) : IEventHandlerFactory { - private readonly IEventSubscriptionManager _subscriptionManager; + private readonly IEventSubscriptionManager _subscriptionManager = subscriptionManager; private readonly ConcurrentDictionary> _eventHandlers = new(); - private readonly IServiceProvider _serviceProvider; - - public DefaultEventHandlerFactory(IEventSubscriptionManager subscriptionManager, IServiceProvider serviceProvider) - { - _subscriptionManager = subscriptionManager; - _serviceProvider = serviceProvider; - } + private readonly IServiceProvider _serviceProvider = serviceProvider; [RequiresUnreferencedCode("Unreferenced code may be used")] public ICollection GetHandlers(Type eventType) @@ -34,14 +28,9 @@ public ICollection GetHandlers(Type eventType) } } -public sealed class DependencyInjectionEventHandlerFactory : IEventHandlerFactory +public sealed class DependencyInjectionEventHandlerFactory(IServiceProvider? serviceProvider = null) : IEventHandlerFactory { - private readonly IServiceProvider _serviceProvider; - - public DependencyInjectionEventHandlerFactory(IServiceProvider? serviceProvider = null) - { - _serviceProvider = serviceProvider ?? DependencyResolver.Current; - } + private readonly IServiceProvider _serviceProvider = serviceProvider ?? DependencyResolver.Current; [RequiresUnreferencedCode("Unreferenced code may be used")] public ICollection GetHandlers(Type eventType) diff --git a/src/WeihanLi.Common/Event/EventQueuePublisher.cs b/src/WeihanLi.Common/Event/EventQueuePublisher.cs index 962506ee..f3215d43 100644 --- a/src/WeihanLi.Common/Event/EventQueuePublisher.cs +++ b/src/WeihanLi.Common/Event/EventQueuePublisher.cs @@ -5,17 +5,11 @@ namespace WeihanLi.Common.Event; -public class EventQueuePublisher : IEventPublisher +public class EventQueuePublisher(IEventQueue eventQueue, IOptions options) : IEventPublisher { - private readonly IEventQueue _eventQueue; + private readonly IEventQueue _eventQueue = eventQueue; - private readonly EventQueuePublisherOptions _options; - - public EventQueuePublisher(IEventQueue eventQueue, IOptions options) - { - _eventQueue = eventQueue; - _options = options.Value; - } + private readonly EventQueuePublisherOptions _options = options.Value; public virtual bool Publish(TEvent @event) where TEvent : class, IEventBase diff --git a/src/WeihanLi.Common/Event/EventSubscriptionManager.cs b/src/WeihanLi.Common/Event/EventSubscriptionManager.cs index 741312a6..c9e9253b 100644 --- a/src/WeihanLi.Common/Event/EventSubscriptionManager.cs +++ b/src/WeihanLi.Common/Event/EventSubscriptionManager.cs @@ -22,7 +22,7 @@ public sealed class EventSubscriptionManagerInMemory : IEventSubscriptionManager public bool Subscribe(Type eventType, Type eventHandlerType) { - var handlers = _eventHandlers.GetOrAdd(eventType, new ConcurrentSet()); + var handlers = _eventHandlers.GetOrAdd(eventType, []); return handlers.TryAdd(eventHandlerType); } diff --git a/src/WeihanLi.Common/Extensions/CollectionExtension.cs b/src/WeihanLi.Common/Extensions/CollectionExtension.cs index 0fb7c5fc..4df9ad0f 100644 --- a/src/WeihanLi.Common/Extensions/CollectionExtension.cs +++ b/src/WeihanLi.Common/Extensions/CollectionExtension.cs @@ -51,9 +51,9 @@ public static string ToQueryString(this NameValueCollection? source) { continue; } - sb.Append("&"); + sb.Append('&'); sb.Append(key.UrlEncode()); - sb.Append("="); + sb.Append('='); var val = source.Get(key); if (val != null) { diff --git a/src/WeihanLi.Common/Extensions/ConfigurationExtension.cs b/src/WeihanLi.Common/Extensions/ConfigurationExtension.cs index 96a5890c..b578e203 100644 --- a/src/WeihanLi.Common/Extensions/ConfigurationExtension.cs +++ b/src/WeihanLi.Common/Extensions/ConfigurationExtension.cs @@ -1,4 +1,5 @@ -using System.Text.RegularExpressions; +using System.Diagnostics.CodeAnalysis; +using System.Text.RegularExpressions; using WeihanLi.Common; using WeihanLi.Extensions; @@ -107,9 +108,7 @@ public static string GetRequiredAppSetting(this IConfiguration configuration, st /// The connection string value public static string GetRequiredConnectionString(this IConfiguration configuration, string name) { - var connString = configuration.GetConnectionString(name); - if (connString is null) - throw new InvalidOperationException("Connection string not exists"); + var connString = configuration.GetConnectionString(name) ?? throw new InvalidOperationException("Connection string not exists"); return connString; } @@ -133,6 +132,7 @@ public static string GetAppSetting(this IConfiguration configuration, string key /// IConfiguration instance /// appSettings key /// app setting value + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T GetAppSetting(this IConfiguration configuration, string key) { return configuration.GetAppSetting(key).To(); @@ -146,6 +146,7 @@ public static T GetAppSetting(this IConfiguration configuration, string key) /// appSettings key /// default value if not exist /// app setting value + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T GetAppSetting(this IConfiguration configuration, string key, T defaultValue) { return configuration.GetAppSetting(key).ToOrDefault(defaultValue); @@ -159,6 +160,7 @@ public static T GetAppSetting(this IConfiguration configuration, string key, /// appSettings key /// default value func if not exist to get a default value /// app setting value + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T GetAppSetting(this IConfiguration configuration, string key, Func defaultValueFunc) { return configuration.GetAppSetting(key).ToOrDefault(defaultValueFunc); diff --git a/src/WeihanLi.Common/Extensions/CoreExtension.cs b/src/WeihanLi.Common/Extensions/CoreExtension.cs index a4ce2655..a46c8115 100644 --- a/src/WeihanLi.Common/Extensions/CoreExtension.cs +++ b/src/WeihanLi.Common/Extensions/CoreExtension.cs @@ -1758,6 +1758,7 @@ public static T To(this object? @this) /// this. /// The default value factory. /// The given data converted to a T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T ToOrDefault(this object? @this, Func defaultValueFactory) { try @@ -1777,6 +1778,7 @@ public static T ToOrDefault(this object? @this, Func defaultValue /// this. /// The default value factory. /// The given data converted to a T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T ToOrDefault(this object? @this, Func defaultValueFactory) { return @this.ToOrDefault(_ => defaultValueFactory()); @@ -1788,6 +1790,7 @@ public static T ToOrDefault(this object? @this, Func defaultValueFactory) /// this. /// type /// The given data converted to + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static object? ToOrDefault(this object? @this, Type type) { Guard.NotNull(type, nameof(type)); @@ -1807,6 +1810,7 @@ public static T ToOrDefault(this object? @this, Func defaultValueFactory) /// Generic type parameter. /// this. /// The given data converted to a T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? ToOrDefault(this object? @this) { return @this.ToOrDefault(_ => default(T)); @@ -1819,6 +1823,7 @@ public static T ToOrDefault(this object? @this, Func defaultValueFactory) /// this. /// The default value. /// The given data converted to a T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T ToOrDefault(this object? @this, T defaultValue) { return @this.ToOrDefault(_ => defaultValue); @@ -2212,7 +2217,7 @@ public static string Concatenate(this IEnumerable source, Func /// The @this to act on. /// The value. /// true if the value is in the string, false if not. - public static bool Contains(this string @this, string value) => Guard.NotNull(@this, nameof(@this)).IndexOf(value, StringComparison.Ordinal) != -1; + public static bool Contains(this string @this, string value) => Guard.NotNull(@this).IndexOf(value, StringComparison.Ordinal) != -1; /// /// A string extension method that query if this object contains the given value. @@ -2221,7 +2226,7 @@ public static string Concatenate(this IEnumerable source, Func /// The value. /// Type of the comparison. /// true if the value is in the string, false if not. - public static bool Contains(this string @this, string value, StringComparison comparisonType) => Guard.NotNull(@this, nameof(@this)).IndexOf(value, comparisonType) != -1; + public static bool Contains(this string @this, string value, StringComparison comparisonType) => Guard.NotNull(@this).IndexOf(value, comparisonType) != -1; /// /// A string extension method that extracts this object. @@ -2229,7 +2234,7 @@ public static string Concatenate(this IEnumerable source, Func /// The @this to act on. /// The predicate. /// A string. - public static string Extract(this string @this, Func predicate) => new(Guard.NotNull(@this, nameof(@this)).ToCharArray().Where(predicate).ToArray()); + public static string Extract(this string @this, Func predicate) => new(Guard.NotNull(@this).ToCharArray().Where(predicate).ToArray()); /// /// A string extension method that removes the letter. @@ -2237,7 +2242,7 @@ public static string Concatenate(this IEnumerable source, Func /// The @this to act on. /// The predicate. /// A string. - public static string RemoveWhere(this string @this, Func predicate) => new(Guard.NotNull(@this, nameof(@this)).ToCharArray().Where(x => !predicate(x)).ToArray()); + public static string RemoveWhere(this string @this, Func predicate) => new(Guard.NotNull(@this).ToCharArray().Where(x => !predicate(x)).ToArray()); /// /// Replaces the format item in a specified String with the text equivalent of the value of a corresponding @@ -2249,17 +2254,17 @@ public static string Concatenate(this IEnumerable source, Func /// A copy of format in which the format items have been replaced by the String equivalent of the corresponding /// instances of Object in args. /// - public static string FormatWith(this string @this, params object[] values) => string.Format(Guard.NotNull(@this, nameof(@this)), values); + public static string FormatWith(this string @this, params object?[] values) => string.Format(Guard.NotNull(@this), values); /// - /// A string extension method that query if '@this' satisfy the specified pattern. + /// A string extension method that query if '@this' satisfies the specified pattern. /// /// The @this to act on. - /// The pattern to use. Use '*' as wildcard string. - /// true if '@this' satisfy the specified pattern, false if not. + /// The pattern to use. Use '*' as a wildcard string. + /// true if '@this' satisfies the specified pattern, false if not. public static bool IsLike(this string @this, string pattern) { - // Turn the pattern into regex pattern, and match the whole string with ^$ + // Turn the pattern into a regex pattern, and match the whole string with ^$ var regexPattern = "^" + Regex.Escape(pattern) + "$"; // Escape special character ?, #, *, [], and [!] @@ -2270,7 +2275,7 @@ public static bool IsLike(this string @this, string pattern) .Replace(@"\*", ".*") .Replace(@"\#", @"\d"); - return Regex.IsMatch(Guard.NotNull(@this, nameof(@this)), regexPattern); + return Regex.IsMatch(Guard.NotNull(@this), regexPattern); } /// @@ -2313,7 +2318,7 @@ public static string SafeSubstring(this string str, int startIndex, int length) /// substring public static string Sub(this string @this, int startIndex) { - Guard.NotNull(@this, nameof(@this)); + Guard.NotNull(@this); if (startIndex >= 0) { return @this.SafeSubstring(startIndex); @@ -2333,7 +2338,7 @@ public static string Sub(this string @this, int startIndex) /// The repeated string. public static string Repeat(this string @this, int repeatCount) { - Guard.NotNull(@this, nameof(@this)); + Guard.NotNull(@this); if (@this.Length == 1) { return new string(@this[0], repeatCount); @@ -2378,14 +2383,14 @@ public static string Reverse(this string? @this) /// /// An array whose elements contain the substrings in this string that are delimited by the separator. /// - public static string[] Split(this string @this, string separator, StringSplitOptions option = StringSplitOptions.None) => Guard.NotNull(@this, nameof(@this)).Split(new[] { separator }, option); + public static string[] Split(this string @this, string separator, StringSplitOptions option = StringSplitOptions.None) => Guard.NotNull(@this).Split(new[] { separator }, option); /// /// A string extension method that converts the @this to a byte array. /// /// The @this to act on. /// @this as a byte[]. - public static byte[] ToByteArray(this string @this) => Encoding.UTF8.GetBytes(Guard.NotNull(@this, nameof(@this))); + public static byte[] ToByteArray(this string @this) => Encoding.UTF8.GetBytes(Guard.NotNull(@this)); /// /// A string extension method that converts the @this to a byte array. @@ -2393,7 +2398,7 @@ public static string Reverse(this string? @this) /// The @this to act on. /// encoding /// @this as a byte[]. - public static byte[] ToByteArray(this string @this, Encoding encoding) => encoding.GetBytes(Guard.NotNull(@this, nameof(@this))); + public static byte[] ToByteArray(this string @this, Encoding encoding) => encoding.GetBytes(Guard.NotNull(@this)); public static byte[] GetBytes(this string str) => Guard.NotNull(str, nameof(str)).GetBytes(null); @@ -2405,14 +2410,14 @@ public static string Reverse(this string? @this) /// Generic type parameter. /// The @this to act on. /// @this as a T. - public static T ToEnum(this string @this) => (T)Enum.Parse(typeof(T), Guard.NotNull(@this, nameof(@this))); + public static T ToEnum(this string @this) => (T)Enum.Parse(typeof(T), Guard.NotNull(@this)); /// /// A string extension method that converts the @this to a title case. /// /// The @this to act on. /// @this as a string. - public static string ToTitleCase(this string @this) => new CultureInfo("en-US").TextInfo.ToTitleCase(Guard.NotNull(@this, nameof(@this))); + public static string ToTitleCase(this string @this) => new CultureInfo("en-US").TextInfo.ToTitleCase(Guard.NotNull(@this)); /// /// A string extension method that converts the @this to a title case. @@ -2420,7 +2425,7 @@ public static string Reverse(this string? @this) /// The @this to act on. /// Information describing the culture. /// @this as a string. - public static string ToTitleCase(this string @this, CultureInfo cultureInfo) => cultureInfo.TextInfo.ToTitleCase(Guard.NotNull(@this, nameof(@this))); + public static string ToTitleCase(this string @this, CultureInfo cultureInfo) => cultureInfo.TextInfo.ToTitleCase(Guard.NotNull(@this)); /// /// A string extension method that truncates. @@ -2428,7 +2433,7 @@ public static string Reverse(this string? @this) /// The @this to act on. /// The maximum length. /// A string. - public static string Truncate(this string @this, int maxLength) => Guard.NotNull(@this, nameof(@this)).Truncate(maxLength, "..."); + public static string Truncate(this string @this, int maxLength) => Guard.NotNull(@this).Truncate(maxLength, "..."); /// /// A string extension method that truncates. diff --git a/src/WeihanLi.Common/Extensions/DataExtension.cs b/src/WeihanLi.Common/Extensions/DataExtension.cs index 40de1eda..78296161 100644 --- a/src/WeihanLi.Common/Extensions/DataExtension.cs +++ b/src/WeihanLi.Common/Extensions/DataExtension.cs @@ -14,14 +14,9 @@ namespace WeihanLi.Extensions; public static partial class DataExtension { - private sealed class DbParameterReadOnlyCollection : IReadOnlyCollection + private sealed class DbParameterReadOnlyCollection(DbParameterCollection parameterCollection) : IReadOnlyCollection { - private readonly DbParameterCollection _paramCollection; - - public DbParameterReadOnlyCollection(DbParameterCollection parameterCollection) - { - _paramCollection = parameterCollection; - } + private readonly DbParameterCollection _paramCollection = parameterCollection; public int Count => _paramCollection.Count; @@ -47,10 +42,7 @@ IEnumerator IEnumerable.GetEnumerator() public static DataTable ToDataTable<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(this IEnumerable entities) { - if (null == entities) - { - throw new ArgumentNullException(nameof(entities)); - } + Guard.NotNull(entities); var properties = CacheUtil.GetTypeProperties(typeof(T)) .Where(_ => _.CanRead) .ToArray(); @@ -83,6 +75,7 @@ IEnumerator IEnumerable.GetEnumerator() /// Generic type parameter. /// The @this to act on. /// @this as an IEnumerable<T> + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static IEnumerable ToEntities(this DataTable @this) { if (@this.Columns.Count > 0) @@ -132,6 +125,7 @@ public static IEnumerable ToExpandoObjects(this DataTable @this) /// The dataTable to act on. /// column index /// @this as an IEnumerable<T> + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static IEnumerable ColumnToList(this DataTable dataTable, int index) { Guard.NotNull(dataTable, nameof(dataTable)); @@ -154,7 +148,7 @@ public static IEnumerable ToExpandoObjects(this DataTable @this) /// Generic type parameter. /// The @this to act on. /// @this as a T. - public static T ToEntity(this DataRow dr) + public static T ToEntity<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] T>(this DataRow dr) { var type = typeof(T); var properties = CacheUtil.GetTypeProperties(type).Where(p => p.CanWrite).ToArray(); @@ -226,6 +220,7 @@ public static DataTable ToDataTable(this IDataReader @this) /// Generic type parameter. /// The @this to act on. /// @this as an IEnumerable<T> + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static IEnumerable ToEntities(this IDataReader @this) { var type = typeof(T); @@ -252,6 +247,7 @@ public static IEnumerable ToEntities(this IDataReader @this) /// The @this to act on. /// whether the DataReader had read /// @this as a T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? ToEntity(this IDataReader @this, bool hadRead = false) { if (!hadRead) @@ -465,6 +461,7 @@ public static async Task ExecuteDataTableAsync(this DbCommand @this, Func< /// Generic type parameter. /// The @this to act on. /// A T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T ExecuteScalarTo(this DbCommand @this) => @this.ExecuteScalar().To(); /// @@ -474,6 +471,7 @@ public static async Task ExecuteDataTableAsync(this DbCommand @this, Func< /// The @this to act on. /// /// A T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static async Task ExecuteScalarToAsync(this DbCommand @this, CancellationToken cancellationToken = default) => (await @this.ExecuteScalarAsync(cancellationToken)).To(); /// @@ -482,6 +480,7 @@ public static async Task ExecuteDataTableAsync(this DbCommand @this, Func< /// Generic type parameter. /// The @this to act on. /// A T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? ExecuteScalarToOrDefault(this DbCommand @this) => @this.ExecuteScalar().ToOrDefault(); /// @@ -491,6 +490,7 @@ public static async Task ExecuteDataTableAsync(this DbCommand @this, Func< /// The @this to act on. /// /// A T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static async Task ExecuteScalarToOrDefaultAsync(this DbCommand @this, CancellationToken cancellationToken = default) => (await @this.ExecuteScalarAsync(cancellationToken)).ToOrDefault(); /// @@ -500,6 +500,7 @@ public static async Task ExecuteDataTableAsync(this DbCommand @this, Func< /// The @this to act on. /// The default value factory. /// A T. + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? ExecuteScalarTo(this DbCommand @this, Func func) { return func(@this.ExecuteScalar()); @@ -543,7 +544,7 @@ public static void AttachDbParameters(this DbCommand command, object? paramInfo) if (paramInfo != null) { var paramType = paramInfo.GetType(); - if (!(paramInfo is IDictionary parameters)) + if (paramInfo is not IDictionary parameters) { if (paramType.IsValueTuple()) // Tuple { @@ -582,7 +583,7 @@ private static string GetParameterName(string originName) case '@': case ':': case '?': - return originName.Substring(1); + return originName[1..]; } } return originName; diff --git a/src/WeihanLi.Common/Extensions/DictionaryExtension.cs b/src/WeihanLi.Common/Extensions/DictionaryExtension.cs index c35fec38..2d5439a7 100644 --- a/src/WeihanLi.Common/Extensions/DictionaryExtension.cs +++ b/src/WeihanLi.Common/Extensions/DictionaryExtension.cs @@ -2,6 +2,7 @@ using System.Data; using System.Data.Common; using System.Text; +using WeihanLi.Common; // ReSharper disable once CheckNamespace namespace WeihanLi.Extensions; @@ -109,11 +110,12 @@ public static bool AddIfNotContainsKey(this IDictionary public static TValue GetOrAdd(this IDictionary @this, TKey key, TValue value) { - if (!@this.ContainsKey(key)) + if (!@this.TryGetValue(key, out var val)) { @this.Add(key, value); + val = value; } - return @this[key]; + return val; } /// @@ -184,13 +186,13 @@ public static TValue AddOrUpdate(this IDictionary @t /// public static TValue AddOrUpdate(this IDictionary @this, TKey key, TValue addValue, Func updateValueFactory) { - if (!@this.ContainsKey(key)) + if (!@this.TryGetValue(key, out var value)) { @this.Add(new KeyValuePair(key, addValue)); } else { - @this[key] = updateValueFactory(key, @this[key]); + @this[key] = updateValueFactory(key, value); } return @this[key]; @@ -216,13 +218,13 @@ public static TValue AddOrUpdate(this IDictionary @t /// public static TValue AddOrUpdate(this IDictionary @this, TKey key, Func addValueFactory, Func updateValueFactory) { - if (!@this.ContainsKey(key)) + if (!@this.TryGetValue(key, out var value)) { @this.Add(new KeyValuePair(key, addValueFactory(key))); } else { - @this[key] = updateValueFactory(key, @this[key]); + @this[key] = updateValueFactory(key, value); } return @this[key]; @@ -319,7 +321,7 @@ public static NameValueCollection ToNameValueCollection(this IDictionary @thi /// public static DataTable ToDataTable(this IDictionary dictionary) { - if (null == dictionary) - { - throw new ArgumentNullException(nameof(dictionary)); - } + Guard.NotNull(dictionary); var dataTable = new DataTable(); if (dictionary.Keys.Count == 0) { @@ -447,9 +446,9 @@ public static string ToQueryString(this IEnumerable { continue; } - sb.Append("&"); + sb.Append('&'); sb.Append(item.Key.UrlEncode()); - sb.Append("="); + sb.Append('='); if (item.Value.IsNotNullOrEmpty()) sb.Append(item.Value.UrlEncode()); } diff --git a/src/WeihanLi.Common/Extensions/EnumerableExtension.cs b/src/WeihanLi.Common/Extensions/EnumerableExtension.cs index fc5c3630..0b920236 100644 --- a/src/WeihanLi.Common/Extensions/EnumerableExtension.cs +++ b/src/WeihanLi.Common/Extensions/EnumerableExtension.cs @@ -156,15 +156,10 @@ public static IEnumerable Distinct(this IEnumerable source, Func source.Distinct(new DynamicEqualityComparer(comparer)); // https://github.com/aspnet/EntityFrameworkCore/blob/release/3.0/src/EFCore.SqlServer/Utilities/EnumerableExtensions.cs - private sealed class DynamicEqualityComparer : IEqualityComparer + private sealed class DynamicEqualityComparer(Func func) : IEqualityComparer where T : class { - private readonly Func _func; - - public DynamicEqualityComparer(Func func) - { - _func = func; - } + private readonly Func _func = func; public bool Equals(T? x, T? y) => _func(x, y); @@ -313,12 +308,11 @@ public static IEnumerable> GroupByEquality(this IEnu return groups; } - private sealed class Grouping : IGrouping + private sealed class Grouping(TKey key) : IGrouping { - private readonly List _items = new(); - public Grouping(TKey key) => Key = key ?? throw new ArgumentNullException(nameof(key)); + private readonly List _items = []; - public TKey Key { get; } + public TKey Key { get; } = Guard.NotNull(key); public void Add(T t) => _items.Add(t); diff --git a/src/WeihanLi.Common/Extensions/ExpressionExtension.cs b/src/WeihanLi.Common/Extensions/ExpressionExtension.cs index 096c1b76..3ae06d82 100644 --- a/src/WeihanLi.Common/Extensions/ExpressionExtension.cs +++ b/src/WeihanLi.Common/Extensions/ExpressionExtension.cs @@ -54,16 +54,10 @@ public static Expression> AndIf(this Expression> Expression.AndAlso(Guard.NotNull(left), Guard.NotNull(right)), parameter); } - private sealed class ReplaceExpressionVisitor : ExpressionVisitor + private sealed class ReplaceExpressionVisitor(Expression oldValue, Expression newValue) : ExpressionVisitor { - private readonly Expression _oldValue; - private readonly Expression _newValue; - - public ReplaceExpressionVisitor(Expression oldValue, Expression newValue) - { - _oldValue = oldValue; - _newValue = newValue; - } + private readonly Expression _oldValue = oldValue; + private readonly Expression _newValue = newValue; public override Expression? Visit(Expression? node) { @@ -76,12 +70,9 @@ public ReplaceExpressionVisitor(Expression oldValue, Expression newValue) public static MethodInfo GetMethod(this Expression expression) { - if (expression == null) - { - throw new ArgumentNullException(nameof(expression)); - } + Guard.NotNull(expression); - if (!(expression.Body is MethodCallExpression methodCallExpression)) + if (expression.Body is not MethodCallExpression methodCallExpression) { throw new InvalidCastException("Cannot be converted to MethodCallExpression"); } @@ -139,11 +130,7 @@ public static MemberInfo GetMemberInfo(this Expression /// - private sealed class BasicAuthenticationHeaderValue : AuthenticationHeaderValue + /// + /// Initializes a new instance of the class. + /// + /// Name of the user. + /// The password. + private sealed class BasicAuthenticationHeaderValue(string userName, string password) : AuthenticationHeaderValue("Basic", EncodeCredential(userName, password)) { - /// - /// Initializes a new instance of the class. - /// - /// Name of the user. - /// The password. - public BasicAuthenticationHeaderValue(string userName, string password) : base("Basic", EncodeCredential(userName, password)) - { - } - private static string EncodeCredential(string userName, string password) { - if (string.IsNullOrWhiteSpace(userName)) - { - throw new ArgumentNullException(nameof(userName)); - } + Guard.NotNullOrWhiteSpace(userName); return Convert.ToBase64String($"{UrlEncode(userName)}:{UrlEncode(password)}".ToByteArray()); } diff --git a/src/WeihanLi.Common/Extensions/HttpRequesterExtension.cs b/src/WeihanLi.Common/Extensions/HttpRequesterExtension.cs index 7c9ab8fb..8f90ebd7 100644 --- a/src/WeihanLi.Common/Extensions/HttpRequesterExtension.cs +++ b/src/WeihanLi.Common/Extensions/HttpRequesterExtension.cs @@ -83,6 +83,7 @@ public static IHttpRequester WithFiles(this IHttpRequester httpRequester, IEnume public static string Execute(this IHttpRequester httpRequester) => httpRequester.ExecuteBytes().GetString(); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? Execute(this IHttpRequester httpRequester, T? defaultVal = default) => httpRequester.ExecuteBytes().GetString().ToOrDefault(defaultVal); public static Task ExecuteAsync(this IHttpRequester httpRequester) @@ -90,6 +91,7 @@ public static Task ExecuteAsync(this IHttpRequester httpRequester) return httpRequester.ExecuteBytesAsync().ContinueWith(r => r.Result.GetString()); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static Task ExecuteAsync(this IHttpRequester httpRequester, T? defaultVal = default) { return httpRequester.ExecuteBytesAsync().ContinueWith(r => r.Result.GetString().ToOrDefault(defaultVal)); diff --git a/src/WeihanLi.Common/Extensions/ILGeneratorExtensions.cs b/src/WeihanLi.Common/Extensions/ILGeneratorExtensions.cs index e1a74cee..0ef63086 100644 --- a/src/WeihanLi.Common/Extensions/ILGeneratorExtensions.cs +++ b/src/WeihanLi.Common/Extensions/ILGeneratorExtensions.cs @@ -161,7 +161,7 @@ private static void EmitNullableToNullableConversion(this ILGenerator ilGenerato var nnTypeTo = typeTo.GetNonNullableType(); ilGenerator.EmitConvertToType(nnTypeFrom, nnTypeTo, isChecked); // construct result type - var ci = typeTo.GetConstructor(new[] { nnTypeTo }); + var ci = typeTo.GetConstructor([nnTypeTo]); ilGenerator.Emit(OpCodes.Newobj, ci!); ilGenerator.Emit(OpCodes.Stloc, locTo); var labEnd = ilGenerator.DefineLabel(); @@ -217,7 +217,7 @@ private static void EmitNonNullableToNullableConversion(this ILGenerator ilGener var locTo = ilGenerator.DeclareLocal(typeTo); var nnTypeTo = typeTo.Unwrap(); ilGenerator.EmitConvertToType(typeFrom, nnTypeTo, isChecked); - var ci = Guard.NotNull(typeTo.GetConstructor(new[] { nnTypeTo })!, "constructor"); + var ci = Guard.NotNull(typeTo.GetConstructor([nnTypeTo])!, "constructor"); ilGenerator.Emit(OpCodes.Newobj, ci); ilGenerator.Emit(OpCodes.Stloc, locTo); ilGenerator.Emit(OpCodes.Ldloc, locTo); @@ -613,7 +613,7 @@ public static void EmitDefaultValue(this ILGenerator ilGenerator, Type type) case TypeCode.Decimal: ilGenerator.Emit(OpCodes.Ldc_I4_0); - ilGenerator.Emit(OpCodes.Newobj, typeof(decimal).GetTypeInfo().GetConstructor(new[] { typeof(int) })!); + ilGenerator.Emit(OpCodes.Newobj, typeof(decimal).GetTypeInfo().GetConstructor([typeof(int)])!); break; default: @@ -793,14 +793,10 @@ internal static bool IsUnsigned(Type type) internal static bool IsFloatingPoint(Type type) { - switch (Type.GetTypeCode(type.Unwrap())) + return Type.GetTypeCode(type.Unwrap()) switch { - case TypeCode.Single: - case TypeCode.Double: - return true; - - default: - return false; - } + TypeCode.Single or TypeCode.Double => true, + _ => false, + }; } } diff --git a/src/WeihanLi.Common/Extensions/JsonSerializeExtension.cs b/src/WeihanLi.Common/Extensions/JsonSerializeExtension.cs index 5f200e5d..210a061e 100644 --- a/src/WeihanLi.Common/Extensions/JsonSerializeExtension.cs +++ b/src/WeihanLi.Common/Extensions/JsonSerializeExtension.cs @@ -1,4 +1,5 @@ using Newtonsoft.Json; +using System.Diagnostics.CodeAnalysis; using WeihanLi.Common; // ReSharper disable once CheckNamespace @@ -120,6 +121,7 @@ public static string ToJsonOrString(this object? obj) /// Type /// 字符串 /// + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T StringToType(this string jsonString) { if (typeof(T) == typeof(string)) @@ -140,6 +142,7 @@ public static T StringToType(this string jsonString) /// json string /// defaultValue /// + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T StringToType(this string jsonString, T defaultValue) { if (typeof(T) == typeof(string)) diff --git a/src/WeihanLi.Common/Extensions/ProcessExtension.cs b/src/WeihanLi.Common/Extensions/ProcessExtension.cs index 5f9f1695..c53164b9 100644 --- a/src/WeihanLi.Common/Extensions/ProcessExtension.cs +++ b/src/WeihanLi.Common/Extensions/ProcessExtension.cs @@ -12,6 +12,13 @@ namespace WeihanLi.Extensions; public static class ProcessExtension { + public static ProcessStartInfo WithEnv(this ProcessStartInfo processStartInfo, string name, string value) + { + Guard.NotNull(processStartInfo); + processStartInfo.Environment[name] = value; + return processStartInfo; + } + #if NET6_0_OR_GREATER #else public static Task WaitForExitAsync(this Process process, CancellationToken cancellationToken = default) @@ -19,20 +26,14 @@ public static Task WaitForExitAsync(this Process process, CancellationToken canc Guard.NotNull(process); process.EnableRaisingEvents = true; var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - void EventHandler(object o, EventArgs eventArgs) => tcs.TrySetResult(null); try { process.Exited += EventHandler; - - if (process.StartTime == DateTime.MinValue) - { - process.Start(); - } - tcs.Task.Wait(cancellationToken); } catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested) { + process.TryKill(); tcs.TrySetCanceled(); } catch (Exception ex) @@ -45,6 +46,8 @@ public static Task WaitForExitAsync(this Process process, CancellationToken canc } return tcs.Task; + + void EventHandler(object o, EventArgs eventArgs) => tcs.TrySetResult(null); } #endif @@ -55,10 +58,8 @@ public static Task WaitForExitAsync(this Process process, CancellationToken canc /// process exit code public static int Execute(this ProcessStartInfo processStartInfo) { - using var process = new Process() - { - StartInfo = processStartInfo - }; + using var process = new Process(); + process.StartInfo = processStartInfo; process.Start(); process.WaitForExit(); return process.ExitCode; @@ -72,12 +73,12 @@ public static int Execute(this ProcessStartInfo processStartInfo) /// process exit code public static async Task ExecuteAsync(this ProcessStartInfo processStartInfo, CancellationToken cancellationToken = default) { - using var process = new Process() - { - StartInfo = processStartInfo - }; + using var process = new Process(); + process.StartInfo = processStartInfo; process.Start(); - await process.WaitForExitAsync(cancellationToken); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ApplicationHelper.ExitToken); + cts.Token.Register((p) => ((Process)p).TryKill(), process); + await process.WaitForExitAsync(cts.Token); return process.ExitCode; } @@ -105,8 +106,14 @@ public static CommandResult GetResult(this ProcessStartInfo psi) public static async Task GetResultAsync(this ProcessStartInfo psi, CancellationToken cancellationToken = default) { var stdOutStringBuilder = new StringBuilder(); +#if NETSTANDARD2_1 || NET6_0_OR_GREATER + await +#endif using var stdOut = new StringWriter(stdOutStringBuilder); var stdErrStringBuilder = new StringBuilder(); +#if NETSTANDARD2_1 || NET6_0_OR_GREATER + await +#endif using var stdErr = new StringWriter(stdErrStringBuilder); var exitCode = await GetExitCodeAsync(psi, stdOut, stdErr, cancellationToken); return new(exitCode, stdOutStringBuilder.ToString(), stdErrStringBuilder.ToString()); @@ -125,7 +132,8 @@ public static int GetExitCode(this ProcessStartInfo psi, TextWriter? stdOut = nu psi.RedirectStandardOutput = stdOut != null; psi.RedirectStandardError = stdErr != null; psi.UseShellExecute = false; - using var process = new Process { StartInfo = psi }; + using var process = new Process(); + process.StartInfo = psi; process.OutputDataReceived += (_, e) => { if (e.Data != null) @@ -167,7 +175,8 @@ public static async Task GetExitCodeAsync(this ProcessStartInfo psi, TextWr psi.RedirectStandardOutput = stdOut != null; psi.RedirectStandardError = stdErr != null; psi.UseShellExecute = false; - using var process = new Process { StartInfo = psi }; + using var process = new Process(); + process.StartInfo = psi; var stdOutComplete = new TaskCompletionSource(); var stdErrComplete = new TaskCompletionSource(); process.OutputDataReceived += (_, e) => @@ -195,8 +204,26 @@ public static async Task GetExitCodeAsync(this ProcessStartInfo psi, TextWr process.BeginOutputReadLine(); process.BeginErrorReadLine(); - await Task.WhenAll(process.WaitForExitAsync(cancellationToken), stdOutComplete.Task, stdErrComplete.Task); - + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ApplicationHelper.ExitToken); + cts.Token.Register((p) => ((Process)p).TryKill(), process); + await Task.WhenAll(process.WaitForExitAsync(cts.Token), stdOutComplete.Task, stdErrComplete.Task); return process.ExitCode; } + + /// + /// Try kill process + /// + /// + /// + /// + public static bool TryKill(this Process process, bool entireProcessTree = true) + { + return +#if NET6_0_OR_GREATER + process.Try(x => x.Kill(entireProcessTree)) +#else + process.Try(x => x.Kill()) +#endif + ; + } } diff --git a/src/WeihanLi.Common/Extensions/PropertiesExtensions.cs b/src/WeihanLi.Common/Extensions/PropertiesExtensions.cs index ac872760..461b00c3 100644 --- a/src/WeihanLi.Common/Extensions/PropertiesExtensions.cs +++ b/src/WeihanLi.Common/Extensions/PropertiesExtensions.cs @@ -9,7 +9,7 @@ public static class PropertiesExtensions { public static T? GetProperty(this IDictionary properties, string key) { - return Guard.NotNull(properties).TryGetValue(key, out var value) ? (T?)value : default(T); + return Guard.NotNull(properties).TryGetValue(key, out var value) ? (T?)value : default; } public static void SetProperty(this IDictionary properties, string key, T value) @@ -20,7 +20,7 @@ public static void SetProperty(this IDictionary properties, public static T? GetProperty(this IProperties propertiesHolder, string key) { Guard.NotNull(propertiesHolder); - return propertiesHolder.Properties.TryGetValue(key, out var value) ? (T?)value : default(T); + return propertiesHolder.Properties.TryGetValue(key, out var value) ? (T?)value : default; } public static void SetProperty(this IProperties propertiesHolder, string key, T value) diff --git a/src/WeihanLi.Common/Extensions/QueryableExtension.cs b/src/WeihanLi.Common/Extensions/QueryableExtension.cs index 914d2a8d..25d36d02 100644 --- a/src/WeihanLi.Common/Extensions/QueryableExtension.cs +++ b/src/WeihanLi.Common/Extensions/QueryableExtension.cs @@ -107,10 +107,7 @@ public static PagedListResult ToPagedList(this IQueryable source, int p public static IQueryable OrderBy(this IQueryable source, string propertyName, bool isAsc = false) { Guard.NotNull(source); - if (string.IsNullOrWhiteSpace(propertyName)) - { - throw new ArgumentException(nameof(propertyName)); - } + Guard.NotNullOrWhiteSpace(propertyName); var type = typeof(T); var arg = Expression.Parameter(type, "x"); diff --git a/src/WeihanLi.Common/Extensions/ReflectionExtension.cs b/src/WeihanLi.Common/Extensions/ReflectionExtension.cs index e3fc119e..fc47c29b 100644 --- a/src/WeihanLi.Common/Extensions/ReflectionExtension.cs +++ b/src/WeihanLi.Common/Extensions/ReflectionExtension.cs @@ -71,20 +71,14 @@ public static class ReflectionExtension public static bool IsVisibleAndVirtual(this PropertyInfo property) { - if (property == null) - { - throw new ArgumentNullException(nameof(property)); - } + Guard.NotNull(property); return (property.CanRead && property.GetMethod!.IsVisibleAndVirtual()) || (property.CanWrite && property.SetMethod!.IsVisibleAndVirtual()); } public static bool IsVisibleAndVirtual(this MethodInfo method) { - if (method == null) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); if (method.IsStatic || method.IsFinal) { return false; @@ -95,10 +89,7 @@ public static bool IsVisibleAndVirtual(this MethodInfo method) public static bool IsVisible(this MethodBase method) { - if (method == null) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); return method.IsPublic || method.IsFamily || method.IsFamilyOrAssembly; } @@ -108,22 +99,23 @@ public static bool IsVisible(this MethodBase method) /// The @this to act on. /// The custom attribute. public static string GetDisplayName(this MemberInfo @this) - => @this.GetCustomAttribute()?.DisplayName ?? @this.GetCustomAttribute()?.Name ?? @this.Name; + => Guard.NotNull(@this).GetCustomAttribute()?.DisplayName ?? @this.GetCustomAttribute()?.Name ?? @this.Name; /// /// GetColumnName /// /// - public static string GetColumnName(this PropertyInfo propertyInfo) => propertyInfo.GetCustomAttribute()?.Name ?? propertyInfo.Name; + public static string GetColumnName(this PropertyInfo propertyInfo) => Guard.NotNull(propertyInfo).GetCustomAttribute()?.Name ?? propertyInfo.Name; /// /// GetDescription /// /// - public static string GetDescription(this MemberInfo @this) => @this.GetCustomAttribute()?.Description ?? @this.Name; + public static string GetDescription(this MemberInfo @this) => Guard.NotNull(@this).GetCustomAttribute()?.Description ?? @this.Name; public static Func? GetValueGetter(this PropertyInfo propertyInfo) { + Guard.NotNull(propertyInfo); return StrongTypedCache.PropertyValueGetters.GetOrAdd(propertyInfo, prop => { if (!prop.CanRead) @@ -138,6 +130,7 @@ public static string GetDisplayName(this MemberInfo @this) public static Func? GetValueGetter(this PropertyInfo propertyInfo) { + Guard.NotNull(propertyInfo); return CacheUtil.PropertyValueGetters.GetOrAdd(propertyInfo, prop => { if (!prop.CanRead) @@ -156,6 +149,7 @@ public static string GetDisplayName(this MemberInfo @this) public static Action? GetValueSetter(this PropertyInfo propertyInfo) where T : class { + Guard.NotNull(propertyInfo); return StrongTypedCache.PropertyValueSetters.GetOrAdd(propertyInfo, prop => { if (!prop.CanWrite) @@ -205,6 +199,7 @@ public static string GetDisplayName(this MemberInfo @this) /// public static Attribute? GetCustomAttribute(this Assembly element, Type attributeType) { + Guard.NotNull(element); return Attribute.GetCustomAttribute(element, attributeType); } @@ -221,6 +216,7 @@ public static string GetDisplayName(this MemberInfo @this) /// public static Attribute? GetCustomAttribute(this Assembly element, Type attributeType, bool inherit) { + Guard.NotNull(element); return Attribute.GetCustomAttribute(element, attributeType, inherit); } @@ -236,6 +232,7 @@ public static string GetDisplayName(this MemberInfo @this) /// public static Attribute[] GetCustomAttributes(this Assembly element, Type attributeType) { + Guard.NotNull(element); return Attribute.GetCustomAttributes(element, attributeType); } @@ -252,6 +249,7 @@ public static Attribute[] GetCustomAttributes(this Assembly element, Type attrib /// public static Attribute[] GetCustomAttributes(this Assembly element, Type attributeType, bool inherit) { + Guard.NotNull(element); return Attribute.GetCustomAttributes(element, attributeType, inherit); } @@ -265,6 +263,7 @@ public static Attribute[] GetCustomAttributes(this Assembly element, Type attrib /// public static Attribute[] GetCustomAttributes(this Assembly element) { + Guard.NotNull(element); return Attribute.GetCustomAttributes(element); } @@ -280,6 +279,7 @@ public static Attribute[] GetCustomAttributes(this Assembly element) /// public static Attribute[] GetCustomAttributes(this Assembly element, bool inherit) { + Guard.NotNull(element); return Attribute.GetCustomAttributes(element, inherit); } @@ -292,6 +292,7 @@ public static Attribute[] GetCustomAttributes(this Assembly element, bool inheri /// true if a custom attribute of type is applied to ; otherwise, false. public static bool IsDefined(this Assembly element, Type attributeType) { + Guard.NotNull(element); return Attribute.IsDefined(element, attributeType); } @@ -305,6 +306,7 @@ public static bool IsDefined(this Assembly element, Type attributeType) /// true if a custom attribute of type is applied to ; otherwise, false. public static bool IsDefined(this Assembly element, Type attributeType, bool inherit) { + Guard.NotNull(element); return Attribute.IsDefined(element, attributeType, inherit); } } diff --git a/src/WeihanLi.Common/Extensions/ServiceCollectionExtension.cs b/src/WeihanLi.Common/Extensions/ServiceCollectionExtension.cs index 1d521351..ef035eb2 100644 --- a/src/WeihanLi.Common/Extensions/ServiceCollectionExtension.cs +++ b/src/WeihanLi.Common/Extensions/ServiceCollectionExtension.cs @@ -284,13 +284,8 @@ public static IServiceCollection RegisterAssemblyModules( public static IServiceCollection Decorate(this IServiceCollection services, Type serviceType, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type decoratorType) { - var service = services.LastOrDefault(x => x.ServiceType == serviceType); - if (service == null) - { - throw new InvalidOperationException("The service is not registered, service need to be registered before decorating"); - } - - var objectFactory = ActivatorUtilities.CreateFactory(decoratorType, new[] { serviceType }); + var service = services.LastOrDefault(x => x.ServiceType == serviceType) ?? throw new InvalidOperationException("The service is not registered, service need to be registered before decorating"); + var objectFactory = ActivatorUtilities.CreateFactory(decoratorType, [serviceType]); var decoratorService = new ServiceDescriptor(serviceType, sp => objectFactory(sp, new[] { sp.CreateInstance(service) diff --git a/src/WeihanLi.Common/Extensions/StringExtension.cs b/src/WeihanLi.Common/Extensions/StringExtension.cs index e6881725..7549066b 100644 --- a/src/WeihanLi.Common/Extensions/StringExtension.cs +++ b/src/WeihanLi.Common/Extensions/StringExtension.cs @@ -239,7 +239,7 @@ public static string GetValueOrDefault(this string? str, Func getDefault /// str /// /// - public static T[] SplitArray(this string? str, StringSplitOptions splitOptions = StringSplitOptions.None) => SplitArray(str, new[] { ',' }, splitOptions); + public static T[] SplitArray(this string? str, StringSplitOptions splitOptions = StringSplitOptions.None) => SplitArray(str, [','], splitOptions); /// /// split specific separator separated string to T array @@ -253,7 +253,7 @@ public static T[] SplitArray(this string? str, char[] separators, StringSplit { if (string.IsNullOrWhiteSpace(str)) { - return Array.Empty(); + return []; } return Guard.NotNull(str) .Split(separators, splitOptions) @@ -276,7 +276,7 @@ public static T[] SplitArray(this string? str, char[] separators, StringSplit } if (str.StartsWith(start)) { - str = str.Substring(start.Length); + str = str[start.Length..]; } return str; } diff --git a/src/WeihanLi.Common/Extensions/TaskExtension.cs b/src/WeihanLi.Common/Extensions/TaskExtension.cs index 4651c99a..0fe4fde0 100644 --- a/src/WeihanLi.Common/Extensions/TaskExtension.cs +++ b/src/WeihanLi.Common/Extensions/TaskExtension.cs @@ -8,7 +8,7 @@ public static class TaskExtension { public static Task WrapTask(this T t) => Task.FromResult(t); - public static ValueTask WrapValueTask(this T t) => new ValueTask(t); + public static ValueTask WrapValueTask(this T t) => new(t); public static Task AsTask(this CancellationToken cancellationToken) { diff --git a/src/WeihanLi.Common/Extensions/TypeExtension.cs b/src/WeihanLi.Common/Extensions/TypeExtension.cs index 68198a6d..e5fe62cd 100644 --- a/src/WeihanLi.Common/Extensions/TypeExtension.cs +++ b/src/WeihanLi.Common/Extensions/TypeExtension.cs @@ -10,37 +10,37 @@ namespace WeihanLi.Extensions; public static class TypeExtension { private static readonly Type[] BasicTypes = - { - typeof(bool), - - typeof(sbyte), - typeof(byte), - typeof(int), - typeof(uint), - typeof(short), - typeof(ushort), - typeof(long), - typeof(ulong), - typeof(float), - typeof(double), - typeof(decimal), - - typeof(Guid), - - typeof(DateTime),// IsPrimitive:False - typeof(TimeSpan),// IsPrimitive:False - typeof(DateTimeOffset), - - typeof(char), - typeof(string),// IsPrimitive:False + [ + typeof(bool), + + typeof(sbyte), + typeof(byte), + typeof(int), + typeof(uint), + typeof(short), + typeof(ushort), + typeof(long), + typeof(ulong), + typeof(float), + typeof(double), + typeof(decimal), + + typeof(Guid), + + typeof(DateTime),// IsPrimitive:False + typeof(TimeSpan),// IsPrimitive:False + typeof(DateTimeOffset), + + typeof(char), + typeof(string),// IsPrimitive:False #if NET6_0_OR_GREATER - typeof(DateOnly), - typeof(TimeOnly), + typeof(DateOnly), + typeof(TimeOnly), #endif - //typeof(object),// IsPrimitive:False - }; + //typeof(object),// IsPrimitive:False + ]; public static TypeCode GetTypeCode(this Type type) => Type.GetTypeCode(type); diff --git a/src/WeihanLi.Common/Helpers/ActivatorHelper.cs b/src/WeihanLi.Common/Helpers/ActivatorHelper.cs index 3dab28db..7cdfdcff 100644 --- a/src/WeihanLi.Common/Helpers/ActivatorHelper.cs +++ b/src/WeihanLi.Common/Helpers/ActivatorHelper.cs @@ -109,7 +109,7 @@ private static ConstructorMatcher MatchConstructor( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)] Type instanceType, params object?[]? parameters) { - parameters ??= Array.Empty(); + parameters ??= []; var bestLength = -1; diff --git a/src/WeihanLi.Common/Helpers/ApplicationHelper.cs b/src/WeihanLi.Common/Helpers/ApplicationHelper.cs index 587cf52c..db60bd57 100644 --- a/src/WeihanLi.Common/Helpers/ApplicationHelper.cs +++ b/src/WeihanLi.Common/Helpers/ApplicationHelper.cs @@ -11,6 +11,9 @@ public static class ApplicationHelper public static readonly string AppRoot = AppDomain.CurrentDomain.BaseDirectory; + private static CancellationToken? _exitToken; + public static CancellationToken ExitToken => _exitToken ??= InvokeHelper.GetExitTokenInternal(); + public static string MapPath(string virtualPath) => AppRoot + virtualPath.TrimStart('~'); /// @@ -57,8 +60,6 @@ public static LibraryInfo GetLibraryInfo(Assembly assembly) /// public static string? GetDotnetPath() { - var executableName = - $"dotnet{(RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : string.Empty)}"; return ResolvePath("dotnet"); } @@ -155,10 +156,10 @@ private static bool IsInContainer() } private static readonly string ServiceAccountPath = - Path.Combine(new string[] - { + Path.Combine( + [ $"{Path.DirectorySeparatorChar}var", "run", "secrets", "kubernetes.io", "serviceaccount", - }); + ]); private const string ServiceAccountTokenKeyFileName = "token"; private const string ServiceAccountRootCAKeyFileName = "ca.crt"; /// diff --git a/src/WeihanLi.Common/Helpers/AsyncLock.cs b/src/WeihanLi.Common/Helpers/AsyncLock.cs index ae721cbf..f8142e08 100644 --- a/src/WeihanLi.Common/Helpers/AsyncLock.cs +++ b/src/WeihanLi.Common/Helpers/AsyncLock.cs @@ -37,11 +37,9 @@ public void Dispose() #region AsyncLockReleaser - private readonly struct AsyncLockReleaser : IDisposable + private readonly struct AsyncLockReleaser(SemaphoreSlim semaphoreSlim) : IDisposable { - private readonly SemaphoreSlim _semaphoreSlim; - - public AsyncLockReleaser(SemaphoreSlim semaphoreSlim) => _semaphoreSlim = semaphoreSlim; + private readonly SemaphoreSlim _semaphoreSlim = semaphoreSlim; public void Dispose() { diff --git a/src/WeihanLi.Common/Helpers/Base32EncodeHelper.cs b/src/WeihanLi.Common/Helpers/Base32EncodeHelper.cs index 0a6aca04..dc6fe877 100644 --- a/src/WeihanLi.Common/Helpers/Base32EncodeHelper.cs +++ b/src/WeihanLi.Common/Helpers/Base32EncodeHelper.cs @@ -16,12 +16,7 @@ public static class Base32EncodeHelper public static byte[] GetBytes(string base32String, char paddingChar = '=') { - if (string.IsNullOrEmpty(base32String)) - { - throw new ArgumentNullException(nameof(base32String)); - } - - base32String = base32String.TrimEnd(paddingChar); //remove padding characters + base32String = Guard.NotNullOrEmpty(base32String).TrimEnd(paddingChar); //remove padding characters var byteCount = base32String.Length * 5 / 8; //this must be TRUNCATED var returnArray = new byte[byteCount]; diff --git a/src/WeihanLi.Common/Helpers/Base64UrlEncodeHelper.cs b/src/WeihanLi.Common/Helpers/Base64UrlEncodeHelper.cs index 06117f88..77886415 100644 --- a/src/WeihanLi.Common/Helpers/Base64UrlEncodeHelper.cs +++ b/src/WeihanLi.Common/Helpers/Base64UrlEncodeHelper.cs @@ -22,11 +22,7 @@ public static class Base64UrlEncodeHelper /// Base64Url encoding of the UTF8 bytes. public static string Encode(string arg) { - if (arg == null) - { - throw new ArgumentNullException(nameof(arg)); - } - return Encode(arg.GetBytes()); + return Encode(Guard.NotNull(arg).GetBytes()); } /// @@ -41,10 +37,7 @@ public static string Encode(string arg) /// offset or length is negative OR offset plus length is greater than the length of inArray. public static string Encode(byte[] inArray, int offset, int length) { - if (inArray == null) - { - throw new ArgumentNullException(nameof(inArray)); - } + Guard.NotNull(inArray); return Convert.ToBase64String(inArray, offset, length).Split(Base64PadCharacter)[0].Replace(Base64Character62, Base64UrlCharacter62).Replace(Base64Character63, Base64UrlCharacter63); } @@ -58,10 +51,7 @@ public static string Encode(byte[] inArray, int offset, int length) /// offset or length is negative OR offset plus length is greater than the length of inArray. public static string Encode(byte[] inArray) { - if (inArray == null) - { - throw new ArgumentNullException(nameof(inArray)); - } + Guard.NotNull(inArray); return Convert.ToBase64String(inArray, 0, inArray.Length).Split(Base64PadCharacter)[0].Replace(Base64Character62, Base64UrlCharacter62).Replace(Base64Character63, Base64UrlCharacter63); } @@ -71,10 +61,7 @@ public static string Encode(byte[] inArray) /// UTF8 bytes. public static byte[] DecodeBytes(string str) { - if (str == null) - { - throw new ArgumentNullException(nameof(str)); - } + Guard.NotNullOrEmpty(str); str = str.Replace(Base64UrlCharacter62, Base64Character62); str = str.Replace(Base64UrlCharacter63, Base64Character63); switch (str.Length % 4) diff --git a/src/WeihanLi.Common/Helpers/Combinatorics/Permutations.cs b/src/WeihanLi.Common/Helpers/Combinatorics/Permutations.cs index 4bd45833..f6c0b95a 100644 --- a/src/WeihanLi.Common/Helpers/Combinatorics/Permutations.cs +++ b/src/WeihanLi.Common/Helpers/Combinatorics/Permutations.cs @@ -71,7 +71,7 @@ public Permutations(IEnumerable values, IComparer? comparer) /// Comparer used for defining the lexicographic order. public Permutations(IEnumerable values, GenerateOption type, IComparer? comparer) { - _ = values ?? throw new ArgumentNullException(nameof(values)); + Guard.NotNull(values); // Copy information provided and then create a parallel int array of lexicographic // orders that will be used for the actual permutation algorithm. @@ -147,8 +147,7 @@ internal sealed class Enumerator : IEnumerator> /// The source Permutations object. public Enumerator(Permutations source) { - _ = source ?? throw new ArgumentNullException(nameof(source)); - _myParent = source; + _myParent = Guard.NotNull(source); _myLexicographicalOrders = new int[source._myLexicographicOrders.Length]; _myValues = new List(source._myValues.Length); source._myLexicographicOrders.CopyTo(_myLexicographicalOrders, 0); @@ -269,9 +268,7 @@ private bool NextPermutation() /// private void Swap(int i, int j) { - var temp = _myValues[i]; - _myValues[i] = _myValues[j]; - _myValues[j] = temp; + (_myValues[j], _myValues[i]) = (_myValues[i], _myValues[j]); _myKviTemp = _myLexicographicalOrders[i]; _myLexicographicalOrders[i] = _myLexicographicalOrders[j]; _myLexicographicalOrders[j] = _myKviTemp; diff --git a/src/WeihanLi.Common/Helpers/Combinatorics/SmallPrimeUtility.cs b/src/WeihanLi.Common/Helpers/Combinatorics/SmallPrimeUtility.cs index 4b8ca21c..9698ed5b 100644 --- a/src/WeihanLi.Common/Helpers/Combinatorics/SmallPrimeUtility.cs +++ b/src/WeihanLi.Common/Helpers/Combinatorics/SmallPrimeUtility.cs @@ -58,9 +58,8 @@ public static List Factor(int i) /// Resultant, expressed as list of prime factors. public static List DividePrimeFactors(IEnumerable numerator, IEnumerable denominator) { - _ = numerator ?? throw new ArgumentNullException(nameof(numerator)); - _ = denominator ?? throw new ArgumentNullException(nameof(denominator)); - var product = numerator.ToList(); + Guard.NotNull(denominator); + var product = Guard.NotNull(numerator).ToList(); foreach (var prime in denominator) product.Remove(prime); return product; @@ -73,7 +72,7 @@ public static List DividePrimeFactors(IEnumerable numerator, IEnumerab /// Standard long representation. public static BigInteger EvaluatePrimeFactors(IEnumerable value) { - _ = value ?? throw new ArgumentNullException(nameof(value)); + Guard.NotNull(value); BigInteger result = 1; foreach (var prime in value) result *= prime; diff --git a/src/WeihanLi.Common/Helpers/Combinatorics/Variations.cs b/src/WeihanLi.Common/Helpers/Combinatorics/Variations.cs index 87a2ebd7..a75da472 100644 --- a/src/WeihanLi.Common/Helpers/Combinatorics/Variations.cs +++ b/src/WeihanLi.Common/Helpers/Combinatorics/Variations.cs @@ -73,19 +73,12 @@ public IEnumerator> GetEnumerator() => /// /// An enumerator for Variations when the type is set to WithRepetition. /// - private sealed class EnumeratorWithRepetition : IEnumerator> + /// + /// Construct a enumerator with the parent object. + /// + /// The source Variations object. + private sealed class EnumeratorWithRepetition(Variations source) : IEnumerator> { - /// - /// Construct a enumerator with the parent object. - /// - /// The source Variations object. - public EnumeratorWithRepetition(Variations source) - { - _myParent = source; - _myCurrentList = null; - _myListIndexes = null; - } - void IEnumerator.Reset() => throw new NotSupportedException(); /// @@ -168,17 +161,17 @@ private void ComputeCurrent() /// /// Parent object this is an enumerator for. /// - private readonly Variations _myParent; + private readonly Variations _myParent = source; /// /// The current list of values, this is lazy evaluated by the Current property. /// - private List? _myCurrentList; + private List? _myCurrentList = null; /// /// An enumerator of the parents list of lexicographic orderings. /// - private List? _myListIndexes; + private List? _myListIndexes = null; } /// diff --git a/src/WeihanLi.Common/Helpers/LineParser.cs b/src/WeihanLi.Common/Helpers/CommandLineParser.cs similarity index 64% rename from src/WeihanLi.Common/Helpers/LineParser.cs rename to src/WeihanLi.Common/Helpers/CommandLineParser.cs index 7cd0ae63..51a484c5 100644 --- a/src/WeihanLi.Common/Helpers/LineParser.cs +++ b/src/WeihanLi.Common/Helpers/CommandLineParser.cs @@ -5,12 +5,9 @@ namespace WeihanLi.Common.Helpers; -public static class LineParser +public static class CommandLineParser { - [Obsolete("Please use Parse instead", true)] - public static IEnumerable ParseLine(string line, LineParseOptions? options = null) => Parse(line, options); - - public static IEnumerable Parse(string line, LineParseOptions? options = null) + public static IEnumerable ParseLine(string line, LineParseOptions? options = null) { if (string.IsNullOrEmpty(line)) { @@ -89,6 +86,47 @@ public static IEnumerable Parse(string line, LineParseOptions? options = tokenBuilder.Clear(); } } + + public static bool GetBoolArgumentValue(string[] args, string argumentName, bool defaultValue = default) + { + var value = ArgumentInternal(args, argumentName); + return value switch + { + null => defaultValue, + "" or "1" => true, + "0" => false, + _ => bool.Parse(value) + }; + } + + public static string? GetArgumentValue(string[] args, string argumentName, string? defaultValue = default) + { + return ArgumentInternal(args, argumentName) ?? defaultValue; + } + + private static string? ArgumentInternal(string[] args, string argumentName) + { + for (var i = 0; i < args.Length; i++) + { + if (args[i] == $"--{argumentName}" || args[i] == $"-{argumentName}") + { + if (i + 1 == args.Length || args[i + 1].StartsWith('-')) + return string.Empty; + + return args[i + 1]; + } + + if (args[i].StartsWith($"-{argumentName}=", StringComparison.Ordinal) + || args[i].StartsWith($"-{argumentName}:", StringComparison.Ordinal)) + return args[i][$"-{argumentName}=".Length..]; + + if (args[i].StartsWith($"--{argumentName}=", StringComparison.Ordinal) + || args[i].StartsWith($"--{argumentName}:", StringComparison.Ordinal)) + return args[i][$"--{argumentName}=".Length..]; + } + + return null; + } } public sealed class LineParseOptions diff --git a/src/WeihanLi.Common/Helpers/Cron/CalendarHelper.cs b/src/WeihanLi.Common/Helpers/Cron/CalendarHelper.cs index 2052adfd..10012785 100644 --- a/src/WeihanLi.Common/Helpers/Cron/CalendarHelper.cs +++ b/src/WeihanLi.Common/Helpers/Cron/CalendarHelper.cs @@ -29,19 +29,19 @@ internal static class CalendarHelper private const int DaysPer400Years = DaysPer100Years * 4 + 1; // 146097 private static readonly int[] DaysToMonth365 = - { - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 - }; + [ + 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 + ]; private static readonly int[] DaysToMonth366 = - { - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 - }; + [ + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 + ]; private static readonly int[] DaysInMonth = - { - -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 - }; + [ + -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 + ]; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsGreaterThan(int year1, int month1, int day1, int year2, int month2, int day2) diff --git a/src/WeihanLi.Common/Helpers/Cron/CronExpression.cs b/src/WeihanLi.Common/Helpers/Cron/CronExpression.cs index 004c2393..0f4f80b7 100644 --- a/src/WeihanLi.Common/Helpers/Cron/CronExpression.cs +++ b/src/WeihanLi.Common/Helpers/Cron/CronExpression.cs @@ -52,16 +52,16 @@ public sealed class CronExpression : IEquatable internal static readonly CronExpression Secondly = Parse("* * * * * *", CronFormat.IncludeSeconds); private static readonly int[] DeBruijnPositions = - { - 0, 1, 2, 53, 3, 7, 54, 27, - 4, 38, 41, 8, 34, 55, 48, 28, - 62, 5, 39, 46, 44, 42, 22, 9, - 24, 35, 59, 56, 49, 18, 29, 11, - 63, 52, 6, 26, 37, 40, 33, 47, - 61, 45, 43, 21, 23, 58, 17, 10, - 51, 25, 36, 32, 60, 20, 57, 16, - 50, 31, 19, 15, 30, 14, 13, 12 - }; + [ + 0, 1, 2, 53, 3, 7, 54, 27, + 4, 38, 41, 8, 34, 55, 48, 28, + 62, 5, 39, 46, 44, 42, 22, 9, + 24, 35, 59, 56, 49, 18, 29, 11, + 63, 52, 6, 26, 37, 40, 33, 47, + 61, 45, 43, 21, 23, 58, 17, 10, + 51, 25, 36, 32, 60, 20, 57, 16, + 50, 31, 19, 15, 30, 14, 13, 12 + ]; private long _second; // 60 bits -> from 0 bit to 59 bit private long _minute; // 60 bits -> from 0 bit to 59 bit @@ -74,6 +74,7 @@ public sealed class CronExpression : IEquatable private byte _lastMonthOffset; private CronExpressionFlag _flags; + private static readonly char[] separator = [ ' ' ]; private CronExpression() { @@ -88,7 +89,7 @@ private CronExpression() /// public static CronExpression Parse(string expression) { - return expression.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Length == 5 + return expression.Split(separator, StringSplitOptions.RemoveEmptyEntries).Length == 5 ? Parse(expression, CronFormat.Standard) : Parse(expression, CronFormat.IncludeSeconds); } @@ -102,7 +103,7 @@ public static CronExpression Parse(string expression) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe CronExpression Parse(string expression, CronFormat format) { - if (string.IsNullOrEmpty(expression)) throw new ArgumentNullException(nameof(expression)); + Guard.NotNullOrEmpty(expression); fixed (char* value = expression) { @@ -215,11 +216,11 @@ public override string ToString() } /// - /// Determines whether the specified is equal to the current . + /// Determines whether the specified is equal to the current . /// - /// The to compare with the current . + /// The to compare with the current . /// - /// true if the specified is equal to the current ; otherwise, false. + /// true if the specified is equal to the current ; otherwise, false. /// public bool Equals(CronExpression other) { @@ -237,11 +238,11 @@ public bool Equals(CronExpression other) } /// - /// Determines whether the specified is equal to this instance. + /// Determines whether the specified is equal to this instance. /// - /// The to compare with this instance. + /// The to compare with this instance. /// - /// true if the specified is equal to this instance; + /// true if the specified is equal to this instance; /// otherwise, false. /// public override bool Equals(object obj) => Equals(obj as CronExpression); @@ -885,13 +886,13 @@ private static unsafe int GetNumber(ref char* pointer, int[] names) [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowFormatException(CronField field, string format, params object[] args) { - throw new CronFormatException(field, String.Format(format, args)); + throw new CronFormatException(field, string.Format(format, args)); } [MethodImpl(MethodImplOptions.NoInlining)] private static void ThrowFormatException(string format, params object[] args) { - throw new CronFormatException(String.Format(format, args)); + throw new CronFormatException(string.Format(format, args)); } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/WeihanLi.Common/Helpers/Cron/CronField.cs b/src/WeihanLi.Common/Helpers/Cron/CronField.cs index e2fd9352..b118aa94 100644 --- a/src/WeihanLi.Common/Helpers/Cron/CronField.cs +++ b/src/WeihanLi.Common/Helpers/Cron/CronField.cs @@ -27,14 +27,14 @@ namespace WeihanLi.Common.Helpers.Cron; internal sealed class CronField { private static readonly string[] MonthNames = - { - null, "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" - }; + [ + null, "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" + ]; private static readonly string[] DayOfWeekNames = - { - "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" - }; + [ + "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN" + ]; private static readonly int[] MonthNamesArray = new int[MonthNames.Length]; private static readonly int[] DayOfWeekNamesArray = new int[DayOfWeekNames.Length]; @@ -93,7 +93,7 @@ private CronField(string name, int first, int last, int[] names, bool canDefineI CanDefineInterval = canDefineInterval; for (var i = First; i <= Last; i++) { - AllBits = AllBits | (1L << i); + AllBits |= (1L << i); } } diff --git a/src/WeihanLi.Common/Helpers/Cron/CronFormatException.cs b/src/WeihanLi.Common/Helpers/Cron/CronFormatException.cs index 9a1ad372..2f042c10 100644 --- a/src/WeihanLi.Common/Helpers/Cron/CronFormatException.cs +++ b/src/WeihanLi.Common/Helpers/Cron/CronFormatException.cs @@ -25,17 +25,13 @@ namespace WeihanLi.Common.Helpers.Cron; /// /// Represents an exception that's thrown, when invalid Cron expression is given. /// +/// +/// Initializes a new instance of the class with +/// the given message. +/// [Serializable] -internal class CronFormatException : FormatException +internal class CronFormatException(string message) : FormatException(message) { - /// - /// Initializes a new instance of the class with - /// the given message. - /// - public CronFormatException(string message) : base(message) - { - } - internal CronFormatException(CronField field, string message) : this($"{field}: {message}") { } diff --git a/src/WeihanLi.Common/Helpers/DataSerializer.cs b/src/WeihanLi.Common/Helpers/DataSerializer.cs index 8db1519f..8e240feb 100644 --- a/src/WeihanLi.Common/Helpers/DataSerializer.cs +++ b/src/WeihanLi.Common/Helpers/DataSerializer.cs @@ -37,10 +37,7 @@ public virtual byte[] Serialize(T obj) { throw new ArgumentException(Resource.TaskCanNotBeSerialized); } - if (obj is null) - { - throw new ArgumentNullException(nameof(obj)); - } + Guard.NotNull(obj); using var ms = new MemoryStream(); var serializer = new XmlSerializer(typeof(T)); serializer.Serialize(ms, obj); @@ -54,7 +51,7 @@ public virtual T Deserialize(byte[] bytes) { throw new ArgumentException(Resource.TaskCanNotBeSerialized); } - + Guard.NotNull(bytes); using var ms = new MemoryStream(bytes); var serializer = new XmlSerializer(typeof(T)); return (T)serializer.Deserialize(ms)!; @@ -71,6 +68,7 @@ public virtual byte[] Serialize(T obj) { throw new ArgumentException(Resource.TaskCanNotBeSerialized); } + Guard.NotNull(obj); return obj.ToJson().GetBytes(); } @@ -81,31 +79,27 @@ public virtual T Deserialize(byte[] bytes) { throw new ArgumentException(Resource.TaskCanNotBeSerialized); } - - return bytes.GetString().JsonToObject() ?? throw new ArgumentNullException(nameof(bytes)); + Guard.NotNull(bytes); + return bytes.GetString().JsonToObject(); } } -public sealed class CompressDataSerializer : IDataSerializer +public sealed class CompressDataSerializer(IDataSerializer serializer, IDataCompressor compressor) : IDataSerializer { - private readonly IDataSerializer _serializer; - private readonly IDataCompressor _compressor; - - public CompressDataSerializer(IDataSerializer serializer, IDataCompressor compressor) - { - _serializer = serializer ?? throw new ArgumentNullException(nameof(serializer)); - _compressor = compressor ?? throw new ArgumentNullException(nameof(compressor)); - } + private readonly IDataSerializer _serializer = Guard.NotNull(serializer); + private readonly IDataCompressor _compressor = Guard.NotNull(compressor); [RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")] public byte[] Serialize(T obj) { + Guard.NotNull(obj); return _compressor.Compress(_serializer.Serialize(obj)); } [RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")] public T Deserialize(byte[] bytes) { + Guard.NotNull(bytes); return _serializer.Deserialize(_compressor.Decompress(bytes)); } } diff --git a/src/WeihanLi.Common/Helpers/DelegateHelper.cs b/src/WeihanLi.Common/Helpers/DelegateHelper.cs index ce92f837..33227c23 100644 --- a/src/WeihanLi.Common/Helpers/DelegateHelper.cs +++ b/src/WeihanLi.Common/Helpers/DelegateHelper.cs @@ -55,11 +55,7 @@ static DelegateHelper() [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] public static Delegate FromMethod(MethodInfo method, object? target = null) { - if (null == method) - { - throw new ArgumentNullException(nameof(method)); - } - + Guard.NotNull(method); var delegateType = GetDelegateType(method); return method.CreateDelegate(delegateType, target); } @@ -68,10 +64,7 @@ public static Delegate FromMethod(MethodInfo method, object? target = null) [RequiresUnreferencedCode("If some of the generic arguments are annotated (either with DynamicallyAccessedMembersAttribute, or generic constraints), trimming can't validate that the requirements of those annotations are met.")] public static Type GetDelegateType(MethodInfo method) { - if (null == method) - { - throw new ArgumentNullException(nameof(method)); - } + Guard.NotNull(method); var isVoidMethod = method.ReturnType == typeof(void); var parameterTypes = method.GetParameters() .Select(p => p.ParameterType) diff --git a/src/WeihanLi.Common/Helpers/DelegateTextWriter.cs b/src/WeihanLi.Common/Helpers/DelegateTextWriter.cs index 3daa1a7a..2b42860b 100644 --- a/src/WeihanLi.Common/Helpers/DelegateTextWriter.cs +++ b/src/WeihanLi.Common/Helpers/DelegateTextWriter.cs @@ -2,19 +2,12 @@ namespace WeihanLi.Common.Helpers; -public sealed class DelegateTextWriter : TextWriter +public sealed class DelegateTextWriter(Action onLineWritten) : TextWriter { public override Encoding Encoding => Encoding.UTF8; - private readonly Action _onLineWritten; - private readonly StringBuilder _builder; - - public DelegateTextWriter(Action onLineWritten) - { - _onLineWritten = onLineWritten ?? throw new ArgumentNullException(nameof(onLineWritten)); - - _builder = new StringBuilder(); - } + private readonly Action _onLineWritten = Guard.NotNull(onLineWritten); + private readonly StringBuilder _builder = new(); public override void Flush() { diff --git a/src/WeihanLi.Common/Helpers/Encoder.cs b/src/WeihanLi.Common/Helpers/Encoder.cs index 582fc783..0c550e28 100644 --- a/src/WeihanLi.Common/Helpers/Encoder.cs +++ b/src/WeihanLi.Common/Helpers/Encoder.cs @@ -107,7 +107,7 @@ public static long DecodeLong(string codeStr) { bytes.AddRange(Enumerable.Repeat((byte)0, 8 - bytes.Count)); } - return BitConverter.ToInt64(bytes.ToArray(), 0); + return BitConverter.ToInt64([.. bytes], 0); } private static byte[] Decode(string codedStr) @@ -175,7 +175,7 @@ private static string Encode(byte[] bytes) do { result = Charset[(int)(bi % 36)] + result; - bi = bi / 36; + bi /= 36; } while (bi > 0); return result; @@ -235,14 +235,14 @@ public static long DecodeLong(string codeStr) { bytes.AddRange(Enumerable.Repeat((byte)0, 8 - bytes.Count)); } - return BitConverter.ToInt64(bytes.ToArray(), 0); + return BitConverter.ToInt64([.. bytes], 0); } private static byte[] Decode(string codedStr) { if (string.IsNullOrEmpty(codedStr)) { - return Array.Empty(); + return []; } var result = new BigInteger(0); diff --git a/src/WeihanLi.Common/Helpers/EnumHelper.cs b/src/WeihanLi.Common/Helpers/EnumHelper.cs index 406589d1..b7aa82aa 100644 --- a/src/WeihanLi.Common/Helpers/EnumHelper.cs +++ b/src/WeihanLi.Common/Helpers/EnumHelper.cs @@ -16,6 +16,7 @@ public static IReadOnlyList ToIdNameList() where TEnum : Enu }); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static IReadOnlyList> ToIdNameList<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum, TValue>() where TEnum : Enum { var enumType = typeof(TEnum); @@ -37,6 +38,7 @@ public static IReadOnlyList ToIdNameList() where TEnum : Enu }); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static IReadOnlyList> ToIdNameDescList<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields)] TEnum, TValue>() where TEnum : Enum { var enumType = typeof(TEnum); diff --git a/src/WeihanLi.Common/Helpers/ExpressionHelper.cs b/src/WeihanLi.Common/Helpers/ExpressionHelper.cs index fba163de..de792cda 100644 --- a/src/WeihanLi.Common/Helpers/ExpressionHelper.cs +++ b/src/WeihanLi.Common/Helpers/ExpressionHelper.cs @@ -21,7 +21,7 @@ public static Expression> GetPropertySelector(s { var arg = Expression.Parameter(typeof(T), "x"); var property = Expression.Property(arg, propertyName); - var exp = Expression.Lambda>(property, new ParameterExpression[] { arg }); + var exp = Expression.Lambda>(property, [arg]); return exp; } diff --git a/src/WeihanLi.Common/Helpers/HashHelper.cs b/src/WeihanLi.Common/Helpers/HashHelper.cs index 5e06dab4..8ab526d5 100644 --- a/src/WeihanLi.Common/Helpers/HashHelper.cs +++ b/src/WeihanLi.Common/Helpers/HashHelper.cs @@ -132,7 +132,7 @@ public static byte[] GetHashedBytes(HashType type, string str, Encoding encoding Guard.NotNull(str, nameof(str)); if (str == string.Empty) { - return Array.Empty(); + return []; } var bytes = encoding.GetBytes(str); return GetHashedBytes(type, bytes); diff --git a/src/WeihanLi.Common/Helpers/Hosting/AppHost.cs b/src/WeihanLi.Common/Helpers/Hosting/AppHost.cs index a369bcfa..389d0c53 100644 --- a/src/WeihanLi.Common/Helpers/Hosting/AppHost.cs +++ b/src/WeihanLi.Common/Helpers/Hosting/AppHost.cs @@ -53,7 +53,7 @@ public AppHost(IServiceProvider services, IConfiguration configuration) public async Task RunAsync(CancellationToken cancellationToken = default) { LogAppHostMessage(AppHostStartingMessage); - using var hostStopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(InvokeHelper.GetExitToken(), cancellationToken); + using var hostStopTokenSource = CancellationTokenSource.CreateLinkedTokenSource(ApplicationHelper.ExitToken, cancellationToken); #if NET6_0_OR_GREATER var waitForStopTask = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); hostStopTokenSource.Token.Register(() => waitForStopTask.TrySetResult()); @@ -64,7 +64,7 @@ public async Task RunAsync(CancellationToken cancellationToken = default) var exceptions = new List(); var startTimeoutCts = new CancellationTokenSource(_appHostOptions.StartupTimeout); - var hostStartCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, InvokeHelper.GetExitToken(), startTimeoutCts.Token); + var hostStartCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, ApplicationHelper.ExitToken, startTimeoutCts.Token); var hostStartCancellationToken = hostStartCancellationTokenSource.Token; await ForeachService(_hostedLifecycleServices, hostStartCancellationToken, _appHostOptions.ServicesStartConcurrently, !_appHostOptions.ServicesStartConcurrently, exceptions, async (service, cancelToken) => @@ -185,7 +185,7 @@ private static async Task ForeachService( else { // The task encountered an await; add it to a list to run concurrently. - tasks ??= new(); + tasks ??= []; tasks.Add(Task.Run(() => task, token)); } } diff --git a/src/WeihanLi.Common/Helpers/Hosting/AppHostBuilder.cs b/src/WeihanLi.Common/Helpers/Hosting/AppHostBuilder.cs index 962e79fd..749c560d 100644 --- a/src/WeihanLi.Common/Helpers/Hosting/AppHostBuilder.cs +++ b/src/WeihanLi.Common/Helpers/Hosting/AppHostBuilder.cs @@ -59,13 +59,9 @@ public AppHost Build() return new AppHost(services, Configuration); } - private sealed class LoggingBuilder : ILoggingBuilder + private sealed class LoggingBuilder(IServiceCollection services) : ILoggingBuilder { - public LoggingBuilder(IServiceCollection services) - { - Services = services; - } - public IServiceCollection Services { get; } + public IServiceCollection Services { get; } = services; } } diff --git a/src/WeihanLi.Common/Helpers/HttpHelper.cs b/src/WeihanLi.Common/Helpers/HttpHelper.cs index 823cbbab..9b5cd18d 100644 --- a/src/WeihanLi.Common/Helpers/HttpHelper.cs +++ b/src/WeihanLi.Common/Helpers/HttpHelper.cs @@ -1,4 +1,5 @@ -using System.Net; +using System.Diagnostics.CodeAnalysis; +using System.Net; using System.Text; using WeihanLi.Common.Http; using WeihanLi.Extensions; @@ -80,13 +81,23 @@ public static bool IsWellKnownContentHeader(string header) return WellKnownContentHeaders.Contains(header); } - #region WebRequest + private static readonly Lazy SharedHttpClient = new(() => new(new NoProxyHttpClientHandler() + { + UseCookies = false, +#if NET6_0_OR_GREATER + AutomaticDecompression = DecompressionMethods.All +#else + AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate +#endif + })); - private static readonly Lazy SharedHttpClient = new(() => new(new NoProxyHttpClientHandler())); /// - /// Shared HttpClient(no proxy) + /// Shared HttpClient(no proxy, disable cookie, enable auto decompression) /// public static HttpClient HttpClient => SharedHttpClient.Value; + + #region WebRequest + #region HttpGet /// @@ -299,22 +310,28 @@ public static async Task HttpGetForBytesAsync(string url, IEnumerable(string url) => HttpGetString(url).StringToType(); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T HttpGetFor(string url, IEnumerable>? customHeaders) => HttpGetString(url, customHeaders).StringToType(); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T HttpGetFor(string url, IEnumerable>? customHeaders, WebProxy? proxy) => HttpGetString(url, customHeaders, proxy).StringToType(); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static Task HttpGetForAsync(string url) => HttpGetStringAsync(url).ContinueWith(result => result.Result.StringToType()); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static Task HttpGetForAsync(string url, IEnumerable>? customHeaders) => HttpGetStringAsync(url, customHeaders).ContinueWith(result => result.Result.StringToType()); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static Task HttpGetForAsync(string url, IEnumerable>? customHeaders, WebProxy? proxy) => HttpGetStringAsync(url, customHeaders, proxy).ContinueWith(result => result.Result.StringToType()); @@ -367,6 +384,7 @@ public static async Task HttpGetForBytesAsync(string url, IDictionary(string url, IDictionary? parameters) { if (parameters.HasValue()) @@ -376,6 +394,7 @@ public static T HttpGetFor(string url, IDictionary? parameter return HttpGetFor(url); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static async Task HttpGetForAsync(string url, IDictionary? parameters) { if (parameters.HasValue()) @@ -444,15 +463,19 @@ public static Task HttpPostJsonAsync(string url, T data) public static Task HttpPostJsonAsync(string url, T data, Encoding encoding) => HttpPostAsync(url, encoding.GetBytes(data.ToJson())); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static TResponse HttpPostJsonFor(string url, TRequest data) => HttpPostFor(url, Encoding.UTF8.GetBytes(data.ToJson()), true); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static TResponse HttpPostJsonFor(string url, TRequest data, Encoding encoding) => HttpPostFor(url, encoding.GetBytes(data.ToJson()), true); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static Task HttpPostJsonForAsync(string url, TRequest data) => HttpPostForAsync(url, Encoding.UTF8.GetBytes(data.ToJson()), true); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static Task HttpPostJsonForAsync(string url, TRequest data, Encoding encoding) => HttpPostForAsync(url, encoding.GetBytes(data.ToJson()), true); @@ -578,9 +601,11 @@ public static async Task HttpPostAsync(string url, byte[] postData, stri return await request.GetResponseStringSafeAsync(); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T HttpPostFor(string url, byte[] postData, bool isJsonFormat) => HttpPost(url, postData, isJsonFormat).StringToType(); + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static async Task HttpPostForAsync(string url, byte[] postData, bool isJsonFormat) => (await HttpPostAsync(url, postData, isJsonFormat)).StringToType(); @@ -836,7 +861,7 @@ public static string HttpPostFile(string url, IEnumerable /// GetUserAgent @@ -1074,8 +1099,7 @@ public static string GetUserAgent(bool isMobileUserAgent = false) /// GetWeChatUserAgent /// /// - public static string GetWeChatUserAgent() - => WeChatUserAgents[SecurityHelper.Random.Next(WeChatUserAgents.Length)]; + public static string GetWeChatUserAgent() => WeChatUserAgents[SecurityHelper.Random.Next(WeChatUserAgents.Length)]; #endregion UserAgents } diff --git a/src/WeihanLi.Common/Helpers/InvokeHelper.cs b/src/WeihanLi.Common/Helpers/InvokeHelper.cs index fabb2335..2b46697c 100644 --- a/src/WeihanLi.Common/Helpers/InvokeHelper.cs +++ b/src/WeihanLi.Common/Helpers/InvokeHelper.cs @@ -127,7 +127,10 @@ private static void InvokeExitHandler(object? sender, EventArgs? args) } } - public static CancellationToken GetExitToken() => LazyCancellationTokenSource.Value.Token; + [Obsolete("Please use ApplicationHelper.ExitToken instead")] + public static CancellationToken GetExitToken() => GetExitTokenInternal(); + + internal static CancellationToken GetExitTokenInternal() => LazyCancellationTokenSource.Value.Token; public static void TryInvoke(Action action) { diff --git a/src/WeihanLi.Common/Helpers/JsonHelper.cs b/src/WeihanLi.Common/Helpers/JsonHelper.cs new file mode 100644 index 00000000..7d57c99e --- /dev/null +++ b/src/WeihanLi.Common/Helpers/JsonHelper.cs @@ -0,0 +1,33 @@ +// Copyright (c) Weihan Li. All rights reserved. +// Licensed under the Apache license. +#if NET6_0_OR_GREATER + +using System.Text.Encodings.Web; +using System.Text.Json; + +namespace WeihanLi.Common.Helpers; + +public static class JsonHelper +{ + public static JsonSerializerOptions WebOptions => new(JsonSerializerDefaults.Web); + public static JsonSerializerOptions UnsafeEncoderOptions => + new JsonSerializerOptions(JsonSerializerDefaults.General).WithUnsafeEncoder(); + public static JsonSerializerOptions WriteIntendedUnsafeEncoderOptions => + new JsonSerializerOptions(JsonSerializerDefaults.General).WithWriteIntended().WithUnsafeEncoder(); + + public static JsonSerializerOptions WithWriteIntended(this JsonSerializerOptions jsonSerializerOptions) + { + Guard.NotNull(jsonSerializerOptions); + jsonSerializerOptions.WriteIndented = true; + return jsonSerializerOptions; + } + + public static JsonSerializerOptions WithUnsafeEncoder(this JsonSerializerOptions jsonSerializerOptions) + { + Guard.NotNull(jsonSerializerOptions); + jsonSerializerOptions.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; + return jsonSerializerOptions; + } +} + +#endif diff --git a/src/WeihanLi.Common/Helpers/MapHelper.cs b/src/WeihanLi.Common/Helpers/MapHelper.cs index aa4a6962..b1f582d4 100644 --- a/src/WeihanLi.Common/Helpers/MapHelper.cs +++ b/src/WeihanLi.Common/Helpers/MapHelper.cs @@ -7,10 +7,7 @@ public static class MapHelper { public static TTarget Map<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TSource, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TTarget>(TSource source) where TTarget : new() { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + Guard.NotNull(source); var sourceType = typeof(TSource); var destinationType = typeof(TTarget); @@ -43,10 +40,7 @@ public static class MapHelper public static TTarget MapWith<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TSource, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TTarget>(TSource source, params string[] propertiesToMap) where TTarget : new() { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + Guard.NotNull(source); var sourceType = typeof(TSource); var destinationType = typeof(TTarget); var result = new TTarget(); @@ -80,10 +74,7 @@ public static class MapHelper public static TTarget MapWithout<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TSource, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TTarget>(TSource source, params string[] propertiesNoMap) where TTarget : new() { - if (source is null) - { - throw new ArgumentNullException(nameof(source)); - } + Guard.NotNull(source); var sourceType = typeof(TSource); var destinationType = typeof(TTarget); diff --git a/src/WeihanLi.Common/Helpers/NetHelper.cs b/src/WeihanLi.Common/Helpers/NetHelper.cs index a0e0af36..62c822e7 100644 --- a/src/WeihanLi.Common/Helpers/NetHelper.cs +++ b/src/WeihanLi.Common/Helpers/NetHelper.cs @@ -11,11 +11,8 @@ internal sealed class IPNetwork { public IPNetwork(string cidr) { - if (string.IsNullOrWhiteSpace(cidr)) - { - throw new ArgumentNullException(nameof(cidr)); - } - var arr = cidr.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + Guard.NotNullOrWhiteSpace(cidr); + var arr = cidr.Split(separator, StringSplitOptions.RemoveEmptyEntries); if (arr.Length == 0 || arr.Length > 2) { throw new ArgumentException("invalid cidr format", nameof(cidr)); @@ -63,6 +60,8 @@ public IPNetwork(IPAddress prefix, int prefixLength) private byte[] Mask { get; } + internal static readonly char[] separator = ['/']; + public bool Contains(IPAddress address) { if (Prefix.AddressFamily != address.AddressFamily) diff --git a/src/WeihanLi.Common/Helpers/PeriodBatching/PeriodicBatching.cs b/src/WeihanLi.Common/Helpers/PeriodBatching/PeriodicBatching.cs index fd696340..305fc38d 100644 --- a/src/WeihanLi.Common/Helpers/PeriodBatching/PeriodicBatching.cs +++ b/src/WeihanLi.Common/Helpers/PeriodBatching/PeriodicBatching.cs @@ -77,10 +77,10 @@ private void CloseAndFlush() // This is the place where SynchronizationContext.Current is unknown and can be != null // so we prevent possible deadlocks here for sync-over-async downstream implementations - ResetSyncContextAndWait(OnTick); + PeriodicBatching.ResetSyncContextAndWait(OnTick); } - private void ResetSyncContextAndWait(Func taskFactory) + private static void ResetSyncContextAndWait(Func taskFactory) { var prevContext = SynchronizationContext.Current; SynchronizationContext.SetSynchronizationContext(null); diff --git a/src/WeihanLi.Common/Helpers/PeriodBatching/PortableTimer.cs b/src/WeihanLi.Common/Helpers/PeriodBatching/PortableTimer.cs index 1928c241..12656841 100644 --- a/src/WeihanLi.Common/Helpers/PeriodBatching/PortableTimer.cs +++ b/src/WeihanLi.Common/Helpers/PeriodBatching/PortableTimer.cs @@ -27,7 +27,7 @@ internal sealed class PortableTimer : IDisposable public PortableTimer(Func onTick) { - _onTick = onTick ?? throw new ArgumentNullException(nameof(onTick)); + _onTick = Guard.NotNull(onTick); _timer = new Timer(_ => OnTick(), null, Timeout.Infinite, Timeout.Infinite); } diff --git a/src/WeihanLi.Common/Helpers/Pipelines/AsyncPipelineBuilder.cs b/src/WeihanLi.Common/Helpers/Pipelines/AsyncPipelineBuilder.cs index c0b2aaa8..9f1f2535 100644 --- a/src/WeihanLi.Common/Helpers/Pipelines/AsyncPipelineBuilder.cs +++ b/src/WeihanLi.Common/Helpers/Pipelines/AsyncPipelineBuilder.cs @@ -14,15 +14,10 @@ public interface IAsyncPipelineBuilder IAsyncPipelineBuilder New(); } -internal sealed class AsyncPipelineBuilder : IAsyncPipelineBuilder +internal sealed class AsyncPipelineBuilder(Func completeFunc) : IAsyncPipelineBuilder { - private readonly Func _completeFunc; - private readonly List, Func>> _pipelines = new(); - - public AsyncPipelineBuilder(Func completeFunc) - { - _completeFunc = completeFunc; - } + private readonly Func _completeFunc = completeFunc; + private readonly List, Func>> _pipelines = []; public IAsyncPipelineBuilder Use(Func, Func> middleware) { diff --git a/src/WeihanLi.Common/Helpers/Pipelines/PipelineBuilder.cs b/src/WeihanLi.Common/Helpers/Pipelines/PipelineBuilder.cs index 1fc67f3b..2baad7f5 100644 --- a/src/WeihanLi.Common/Helpers/Pipelines/PipelineBuilder.cs +++ b/src/WeihanLi.Common/Helpers/Pipelines/PipelineBuilder.cs @@ -14,15 +14,10 @@ public interface IPipelineBuilder IPipelineBuilder New(); } -internal sealed class PipelineBuilder : IPipelineBuilder +internal sealed class PipelineBuilder(Action completeFunc) : IPipelineBuilder { - private readonly Action _completeFunc; - private readonly List, Action>> _pipelines = new(); - - public PipelineBuilder(Action completeFunc) - { - _completeFunc = completeFunc; - } + private readonly Action _completeFunc = completeFunc; + private readonly List, Action>> _pipelines = []; public IPipelineBuilder Use(Func, Action> middleware) { diff --git a/src/WeihanLi.Common/Helpers/Pipelines/ValueAsyncPipelineBuilder.cs b/src/WeihanLi.Common/Helpers/Pipelines/ValueAsyncPipelineBuilder.cs index b8cd22e6..974621c1 100644 --- a/src/WeihanLi.Common/Helpers/Pipelines/ValueAsyncPipelineBuilder.cs +++ b/src/WeihanLi.Common/Helpers/Pipelines/ValueAsyncPipelineBuilder.cs @@ -13,15 +13,10 @@ public interface IValueAsyncPipelineBuilder IValueAsyncPipelineBuilder New(); } -internal sealed class ValueAsyncPipelineBuilder : IValueAsyncPipelineBuilder +internal sealed class ValueAsyncPipelineBuilder(Func completeFunc) : IValueAsyncPipelineBuilder { - private readonly Func _completeFunc; - private readonly List, Func>> _pipelines = new(); - - public ValueAsyncPipelineBuilder(Func completeFunc) - { - _completeFunc = completeFunc; - } + private readonly Func _completeFunc = completeFunc; + private readonly List, Func>> _pipelines = []; public IValueAsyncPipelineBuilder Use(Func, Func> middleware) { diff --git a/src/WeihanLi.Common/Helpers/ProfilerHelper.cs b/src/WeihanLi.Common/Helpers/ProfilerHelper.cs index b3999b14..2b7f9228 100644 --- a/src/WeihanLi.Common/Helpers/ProfilerHelper.cs +++ b/src/WeihanLi.Common/Helpers/ProfilerHelper.cs @@ -3,16 +3,10 @@ namespace WeihanLi.Common.Helpers; -public sealed class ProfilerStopper : IDisposable +public sealed class ProfilerStopper(IProfiler profiler, Action profileAction) : IDisposable { - private readonly IProfiler _profiler; - private readonly Action _profileAction; - - public ProfilerStopper(IProfiler profiler, Action profileAction) - { - _profiler = profiler ?? throw new ArgumentNullException(nameof(profiler)); - _profileAction = profileAction ?? throw new ArgumentNullException(nameof(profileAction)); - } + private readonly IProfiler _profiler = Guard.NotNull(profiler); + private readonly Action _profileAction = Guard.NotNull(profileAction); public void Dispose() { @@ -21,16 +15,10 @@ public void Dispose() } } -public sealed class StopwatchStopper : IDisposable +public sealed class StopwatchStopper(Stopwatch stopwatch, Action profileAction) : IDisposable { - private readonly Stopwatch _stopwatch; - private readonly Action _profileAction; - - public StopwatchStopper(Stopwatch stopwatch, Action profileAction) - { - _stopwatch = stopwatch ?? throw new ArgumentNullException(nameof(stopwatch)); - _profileAction = profileAction ?? throw new ArgumentNullException(nameof(profileAction)); - } + private readonly Stopwatch _stopwatch = Guard.NotNull(stopwatch); + private readonly Action _profileAction = Guard.NotNull(profileAction); public void Dispose() { @@ -43,13 +31,13 @@ public static class ProfilerHelper { public static StopwatchStopper Profile(this Stopwatch watch, Action profilerAction) { - Guard.NotNull(watch, nameof(watch)).Restart(); + Guard.NotNull(watch).Restart(); return new StopwatchStopper(watch, profilerAction); } public static ProfilerStopper StartNew(this IProfiler profiler, Action profilerAction) { - Guard.NotNull(profiler, nameof(profiler)).Restart(); + Guard.NotNull(profiler).Restart(); return new ProfilerStopper(profiler, profilerAction); } @@ -59,7 +47,7 @@ public static ProfilerStopper StartNew(this IProfiler profiler, Action /// GetElapsedTime /// /// startTimestamp, get by Stopwatch.GetTimestamp() - /// elapsed timespan + /// elapsed time public static TimeSpan GetElapsedTime(long startTimestamp) => #if NET7_0_OR_GREATER Stopwatch.GetElapsedTime(startTimestamp) @@ -73,7 +61,7 @@ public static TimeSpan GetElapsedTime(long startTimestamp) => /// /// startTimestamp, get by Stopwatch.GetTimestamp() /// endTimestamp, get by Stopwatch.GetTimestamp - /// elapsed timespan + /// elapsed time public static TimeSpan GetElapsedTime(long startTimestamp, long endTimestamp) { #if NET7_0_OR_GREATER diff --git a/src/WeihanLi.Common/Helpers/ReflectHelper.cs b/src/WeihanLi.Common/Helpers/ReflectHelper.cs index 4e0c0bf6..5466b317 100644 --- a/src/WeihanLi.Common/Helpers/ReflectHelper.cs +++ b/src/WeihanLi.Common/Helpers/ReflectHelper.cs @@ -22,33 +22,22 @@ public static bool IsAwaitable(this Type type) } } -internal readonly struct AwaitableInfo +internal readonly struct AwaitableInfo( + Type awaiterType, + PropertyInfo awaiterIsCompletedProperty, + MethodInfo awaiterGetResultMethod, + MethodInfo awaiterOnCompletedMethod, + MethodInfo? awaiterUnsafeOnCompletedMethod, + Type resultType, + MethodInfo getAwaiterMethod) { - public Type AwaiterType { get; } - public PropertyInfo AwaiterIsCompletedProperty { get; } - public MethodInfo AwaiterGetResultMethod { get; } - public MethodInfo AwaiterOnCompletedMethod { get; } - public MethodInfo? AwaiterUnsafeOnCompletedMethod { get; } - public Type ResultType { get; } - public MethodInfo GetAwaiterMethod { get; } - - public AwaitableInfo( - Type awaiterType, - PropertyInfo awaiterIsCompletedProperty, - MethodInfo awaiterGetResultMethod, - MethodInfo awaiterOnCompletedMethod, - MethodInfo? awaiterUnsafeOnCompletedMethod, - Type resultType, - MethodInfo getAwaiterMethod) - { - AwaiterType = awaiterType; - AwaiterIsCompletedProperty = awaiterIsCompletedProperty; - AwaiterGetResultMethod = awaiterGetResultMethod; - AwaiterOnCompletedMethod = awaiterOnCompletedMethod; - AwaiterUnsafeOnCompletedMethod = awaiterUnsafeOnCompletedMethod; - ResultType = resultType; - GetAwaiterMethod = getAwaiterMethod; - } + public Type AwaiterType { get; } = awaiterType; + public PropertyInfo AwaiterIsCompletedProperty { get; } = awaiterIsCompletedProperty; + public MethodInfo AwaiterGetResultMethod { get; } = awaiterGetResultMethod; + public MethodInfo AwaiterOnCompletedMethod { get; } = awaiterOnCompletedMethod; + public MethodInfo? AwaiterUnsafeOnCompletedMethod { get; } = awaiterUnsafeOnCompletedMethod; + public Type ResultType { get; } = resultType; + public MethodInfo GetAwaiterMethod { get; } = getAwaiterMethod; [RequiresUnreferencedCode("Members from serialized types may be trimmed if not referenced directly")] public static bool IsTypeAwaitable([DynamicallyAccessedMembers((DynamicallyAccessedMemberTypes.PublicMethods))] Type type, out AwaitableInfo? awaitableInfo) diff --git a/src/WeihanLi.Common/Helpers/SecurityHelper.cs b/src/WeihanLi.Common/Helpers/SecurityHelper.cs index a297a884..a9dca881 100644 --- a/src/WeihanLi.Common/Helpers/SecurityHelper.cs +++ b/src/WeihanLi.Common/Helpers/SecurityHelper.cs @@ -7,57 +7,59 @@ namespace WeihanLi.Common.Helpers; /// public static class SecurityHelper { - private static readonly char[] _constantCharacters = { - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9', - 'a', - 'b', - 'c', - 'd', - 'e', - 'f', - 'g', - 'h', - 'i', - 'j', - 'k', - 'l', - 'm', - 'n', - 'o', - 'p', - 'q', - 'r', - 's', - 't', - 'u', - 'v', - 'w', - 'x', - 'y', - 'z' - }; + private static readonly char[] _constantCharacters = + [ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'i', + 'j', + 'k', + 'l', + 'm', + 'n', + 'o', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z' + ]; - private static readonly char[] _constantNumber = { - '0', - '1', - '2', - '3', - '4', - '5', - '6', - '7', - '8', - '9' - }; + private static readonly char[] _constantNumber = + [ + '0', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9' + ]; #if NET6_0_OR_GREATER public static Random Random => Random.Shared; @@ -73,10 +75,7 @@ public static Random Random { get { - if (_random == null) - { - _random = new(); - } + _random ??= new(); return _random; } } diff --git a/src/WeihanLi.Common/Helpers/StringHelper.cs b/src/WeihanLi.Common/Helpers/StringHelper.cs index 0110cf76..7d6dc80b 100644 --- a/src/WeihanLi.Common/Helpers/StringHelper.cs +++ b/src/WeihanLi.Common/Helpers/StringHelper.cs @@ -35,21 +35,21 @@ public static string HideSensitiveInfo(string? info, int left, int right, int se if (info!.Length - left - right > 0) { - return info.Substring(0, left) + return info[..left] .PadRight(left + sensitiveCharCount, SensitiveChar) - .Insert(left + sensitiveCharCount, info.Substring(info.Length - right)); + .Insert(left + sensitiveCharCount, info[^right..]); } if (basedOnLeft) { return info.Length > left && left > 0 ? info.Remove(left).Insert(left, new string(SensitiveChar, sensitiveCharCount)) - : info.Substring(0, 1).PadRight(1 + sensitiveCharCount, SensitiveChar); + : info[..1].PadRight(1 + sensitiveCharCount, SensitiveChar); } return info.Length > right && right > 0 - ? info.Substring(info.Length - right).PadLeft(right + sensitiveCharCount, SensitiveChar) - : info.Substring(0, 1).PadLeft(1 + sensitiveCharCount, SensitiveChar); + ? info[^right..].PadLeft(right + sensitiveCharCount, SensitiveChar) + : info[..1].PadLeft(1 + sensitiveCharCount, SensitiveChar); } /// @@ -218,8 +218,8 @@ private static string ToSeparatedCase(string s, char separator) return s; } - StringBuilder sb = new StringBuilder(); - SeparatedCaseState state = SeparatedCaseState.Start; + var sb = new StringBuilder(); + var state = SeparatedCaseState.Start; for (var i = 0; i < s.Length; i++) { @@ -285,6 +285,6 @@ public static bool StartsWith(this string? source, char value) public static bool EndsWith(this string source, char value) { - return !string.IsNullOrEmpty(source) && source![source!.Length - 1] == value; + return !string.IsNullOrEmpty(source) && source[^1] == value; } } diff --git a/src/WeihanLi.Common/Helpers/TypeHelper.cs b/src/WeihanLi.Common/Helpers/TypeHelper.cs index 52936bcc..f3877c51 100644 --- a/src/WeihanLi.Common/Helpers/TypeHelper.cs +++ b/src/WeihanLi.Common/Helpers/TypeHelper.cs @@ -6,8 +6,8 @@ public static class TypeHelper { private const char DefaultNestedTypeDelimiter = '+'; - private static readonly Dictionary _builtInTypeNames = new Dictionary - { + private static readonly Dictionary _builtInTypeNames = new() + { { typeof(void), "void" }, { typeof(bool), "bool" }, { typeof(byte), "byte" }, @@ -51,7 +51,7 @@ private static void ProcessType(StringBuilder builder, Type type, in DisplayName { if (type.IsGenericType) { - Type[] genericArguments = type.GetGenericArguments(); + var genericArguments = type.GetGenericArguments(); ProcessGenericType(builder, type, genericArguments, genericArguments.Length, options); } else if (type.IsArray) @@ -83,7 +83,7 @@ private static void ProcessType(StringBuilder builder, Type type, in DisplayName private static void ProcessArrayType(StringBuilder builder, Type type, in DisplayNameOptions options) { - Type innerType = type; + var innerType = type; while (innerType.IsArray) { innerType = innerType.GetElementType()!; @@ -152,22 +152,14 @@ private static void ProcessGenericType(StringBuilder builder, Type type, Type[] } } - private readonly struct DisplayNameOptions + private readonly struct DisplayNameOptions(bool fullName, bool includeGenericParameterNames, bool includeGenericParameters, char nestedTypeDelimiter) { - public DisplayNameOptions(bool fullName, bool includeGenericParameterNames, bool includeGenericParameters, char nestedTypeDelimiter) - { - FullName = fullName; - IncludeGenericParameters = includeGenericParameters; - IncludeGenericParameterNames = includeGenericParameterNames; - NestedTypeDelimiter = nestedTypeDelimiter; - } - - public bool FullName { get; } + public bool FullName { get; } = fullName; - public bool IncludeGenericParameters { get; } + public bool IncludeGenericParameters { get; } = includeGenericParameters; - public bool IncludeGenericParameterNames { get; } + public bool IncludeGenericParameterNames { get; } = includeGenericParameterNames; - public char NestedTypeDelimiter { get; } + public char NestedTypeDelimiter { get; } = nestedTypeDelimiter; } } diff --git a/src/WeihanLi.Common/Helpers/ValidateHelper.cs b/src/WeihanLi.Common/Helpers/ValidateHelper.cs index 974764cc..b094ac80 100644 --- a/src/WeihanLi.Common/Helpers/ValidateHelper.cs +++ b/src/WeihanLi.Common/Helpers/ValidateHelper.cs @@ -97,8 +97,7 @@ public static bool IsIdCard(string id) /// private static bool CheckIDCard18(string? id) { - long n; - if (long.TryParse(id!.Remove(17), out n) == false || n < Math.Pow(10, 16) || long.TryParse(id.Replace('x', '0').Replace('X', '0'), out n) == false) + if (long.TryParse(id!.Remove(17), out var n) == false || n < Math.Pow(10, 16) || long.TryParse(id.Replace('x', '0').Replace('X', '0'), out n) == false) { return false;//数字验证 } @@ -123,7 +122,7 @@ private static bool CheckIDCard18(string? id) } var y = sum % 11; - if (arrVarifyCode[y] != id.Substring(17, 1).ToLower()) + if (!arrVarifyCode[y].Equals(id.Substring(17, 1), StringComparison.CurrentCultureIgnoreCase)) { return false;//校验码验证 } diff --git a/src/WeihanLi.Common/Helpers/ValueStopwatch.cs b/src/WeihanLi.Common/Helpers/ValueStopwatch.cs index 465f43cc..8f5defd7 100644 --- a/src/WeihanLi.Common/Helpers/ValueStopwatch.cs +++ b/src/WeihanLi.Common/Helpers/ValueStopwatch.cs @@ -34,7 +34,7 @@ public TimeSpan Elapsed /// Gets a value indicating whether the timer is running. /// true if the instance is currently running and measuring elapsed time for an interval; otherwise, false. - public bool IsRunning => _stopTimestamp == 0; + public readonly bool IsRunning => _stopTimestamp == 0; /// Stops time interval measurement, resets the elapsed time to zero, and starts measuring elapsed time. public void Restart() diff --git a/src/WeihanLi.Common/Http/HttpRequester.cs b/src/WeihanLi.Common/Http/HttpRequester.cs index a38d4839..9ce5a22e 100644 --- a/src/WeihanLi.Common/Http/HttpRequester.cs +++ b/src/WeihanLi.Common/Http/HttpRequester.cs @@ -50,7 +50,7 @@ public WebRequestHttpRequester(string requestUrl) : this(requestUrl, HttpMethod. /// method public WebRequestHttpRequester(string requestUrl, IDictionary? queryDictionary, HttpMethod method) { - _requestUrl = $"{requestUrl}{(requestUrl.Contains("?") ? "&" : "?")}{queryDictionary.ToQueryString()}"; + _requestUrl = $"{requestUrl}{(requestUrl.Contains('?') ? "&" : "?")}{queryDictionary.ToQueryString()}"; _request = WebRequest.CreateHttp(requestUrl); _request.UserAgent = HttpHelper.GetUserAgent(); @@ -547,7 +547,7 @@ public IHttpRequester WithHeaders(IEnumerable>? cu // are only allowed in the request headers collection and not in the request content headers collection. if (HttpHelper.IsWellKnownContentHeader(header.Key)) { - _request.Content ??= new ByteArrayContent(Array.Empty()); + _request.Content ??= new ByteArrayContent([]); if (header.Value is null) { _request.Content.Headers.Remove(header.Key); diff --git a/src/WeihanLi.Common/Http/JsonHttpContent.cs b/src/WeihanLi.Common/Http/JsonHttpContent.cs index b7ad38d9..fbe6af9e 100644 --- a/src/WeihanLi.Common/Http/JsonHttpContent.cs +++ b/src/WeihanLi.Common/Http/JsonHttpContent.cs @@ -7,7 +7,7 @@ namespace WeihanLi.Common.Http; -public sealed class JsonHttpContent : StringContent +public sealed class JsonHttpContent(string content, Encoding encoding) : StringContent(content, encoding, HttpHelper.ApplicationJsonMediaType) { public JsonHttpContent(object obj, JsonSerializerSettings? jsonSerializerSettings = null) : this(JsonConvert.SerializeObject(obj, jsonSerializerSettings)) @@ -18,10 +18,6 @@ public JsonHttpContent(string content) : this(content, Encoding.UTF8) { } - public JsonHttpContent(string content, Encoding encoding) : base(content, encoding, HttpHelper.ApplicationJsonMediaType) - { - } - public static HttpContent From(object? obj, JsonSerializerSettings? serializerSettings = null) { if (obj is null) diff --git a/src/WeihanLi.Common/Logging/ConsoleLoggingProvider.cs b/src/WeihanLi.Common/Logging/ConsoleLoggingProvider.cs index 6105caa0..7fca3631 100644 --- a/src/WeihanLi.Common/Logging/ConsoleLoggingProvider.cs +++ b/src/WeihanLi.Common/Logging/ConsoleLoggingProvider.cs @@ -28,14 +28,9 @@ public string FormatAsString(LogHelperLoggingEvent loggingEvent) } } -internal sealed class DelegateConsoleLogFormatter : IConsoleLogFormatter +internal sealed class DelegateConsoleLogFormatter(Func formatter) : IConsoleLogFormatter { - private readonly Func _formatter; - - public DelegateConsoleLogFormatter(Func formatter) - { - _formatter = formatter ?? throw new ArgumentNullException(nameof(formatter)); - } + private readonly Func _formatter = Guard.NotNull(formatter); public string FormatAsString(LogHelperLoggingEvent loggingEvent) => _formatter(loggingEvent); } @@ -44,7 +39,7 @@ internal sealed class ConsoleLoggingProvider : ILogHelperProvider { private readonly IConsoleLogFormatter _formatter; - private readonly BlockingCollection _messageQueue = new(); + private readonly BlockingCollection _messageQueue = []; private readonly Thread _outputThread; public ConsoleLoggingProvider(IConsoleLogFormatter formatter) diff --git a/src/WeihanLi.Common/Logging/LogHelperExtensions.cs b/src/WeihanLi.Common/Logging/LogHelperExtensions.cs index 647a76f5..8f82678d 100644 --- a/src/WeihanLi.Common/Logging/LogHelperExtensions.cs +++ b/src/WeihanLi.Common/Logging/LogHelperExtensions.cs @@ -235,7 +235,7 @@ public static void AddProperty(this LogHelperLoggingEvent loggingEvent, string p { Guard.NotNull(loggingEvent, nameof(loggingEvent)); - loggingEvent.Properties ??= new Dictionary(); + loggingEvent.Properties ??= []; if (loggingEvent.Properties.ContainsKey(propertyName) && !overwrite) { return; @@ -250,7 +250,7 @@ public static void AddProperty(this LogHelperLoggingEvent loggingEvent, string p Guard.NotNull(loggingEvent, nameof(loggingEvent)); Guard.NotNull(propertyValueFactory, nameof(propertyValueFactory)); - loggingEvent.Properties ??= new Dictionary(); + loggingEvent.Properties ??= []; if (loggingEvent.Properties.ContainsKey(propertyName) && !overwrite) { diff --git a/src/WeihanLi.Common/Logging/LogHelperFactory.cs b/src/WeihanLi.Common/Logging/LogHelperFactory.cs index 2139f7ae..be7b9198 100644 --- a/src/WeihanLi.Common/Logging/LogHelperFactory.cs +++ b/src/WeihanLi.Common/Logging/LogHelperFactory.cs @@ -27,24 +27,17 @@ private NullLogHelperFactory() public ILogHelperLogger CreateLogger(string categoryName) => NullLogHelperLogger.Instance; } -internal sealed class LogHelperFactory : ILogHelperFactory +internal sealed class LogHelperFactory(IReadOnlyDictionary logHelperProviders, + IReadOnlyCollection logHelperEnrichers, + IReadOnlyCollection> logFilters + ) : ILogHelperFactory { - internal readonly IReadOnlyDictionary _logHelperProviders; - internal readonly IReadOnlyCollection _logHelperEnrichers; - internal readonly IReadOnlyCollection> _logFilters; + internal readonly IReadOnlyDictionary _logHelperProviders = logHelperProviders; + internal readonly IReadOnlyCollection _logHelperEnrichers = logHelperEnrichers; + internal readonly IReadOnlyCollection> _logFilters = logFilters; private readonly ConcurrentDictionary _loggers = new(); - public LogHelperFactory(IReadOnlyDictionary logHelperProviders, - IReadOnlyCollection logHelperEnrichers, - IReadOnlyCollection> logFilters - ) - { - _logHelperProviders = logHelperProviders; - _logHelperEnrichers = logHelperEnrichers; - _logFilters = logFilters; - } - public ILogHelperLogger CreateLogger(string categoryName) => _loggers.GetOrAdd(categoryName, _ => new LogHelper(this, _)); public void Dispose() diff --git a/src/WeihanLi.Common/Logging/LogHelperLogger.cs b/src/WeihanLi.Common/Logging/LogHelperLogger.cs index 37c2530c..e665034f 100644 --- a/src/WeihanLi.Common/Logging/LogHelperLogger.cs +++ b/src/WeihanLi.Common/Logging/LogHelperLogger.cs @@ -28,24 +28,15 @@ public interface ILogHelperLogger : ILogHelperLogger { } -internal sealed class LogHelperGenericLogger : LogHelper, ILogHelperLogger +internal sealed class LogHelperGenericLogger(LogHelperFactory logHelperFactory) : LogHelper(logHelperFactory, typeof(TCategory).FullName ?? typeof(TCategory).Name), ILogHelperLogger { - public LogHelperGenericLogger(LogHelperFactory logHelperFactory) : base(logHelperFactory, typeof(TCategory).FullName ?? typeof(TCategory).Name) - { - } } -internal class LogHelper : ILogHelperLogger +internal class LogHelper(LogHelperFactory logHelperFactory, string categoryName) : ILogHelperLogger { - private readonly LogHelperFactory _logHelperFactory; - - public string CategoryName { get; } + private readonly LogHelperFactory _logHelperFactory = logHelperFactory; - public LogHelper(LogHelperFactory logHelperFactory, string categoryName) - { - _logHelperFactory = logHelperFactory; - CategoryName = categoryName; - } + public string CategoryName { get; } = categoryName; public void Log(LogHelperLogLevel logLevel, Exception? exception, string? messageTemplate, params object?[] parameters) { diff --git a/src/WeihanLi.Common/Logging/LogHelperLoggingEvent.cs b/src/WeihanLi.Common/Logging/LogHelperLoggingEvent.cs index f7c39503..f17914c4 100644 --- a/src/WeihanLi.Common/Logging/LogHelperLoggingEvent.cs +++ b/src/WeihanLi.Common/Logging/LogHelperLoggingEvent.cs @@ -21,7 +21,7 @@ public LogHelperLoggingEvent Copy() var newEvent = (LogHelperLoggingEvent)MemberwiseClone(); if (Properties != null) { - newEvent.Properties = new Dictionary(); + newEvent.Properties = []; foreach (var property in Properties) { newEvent.Properties[property.Key] = property.Value; diff --git a/src/WeihanLi.Common/Logging/LoggerGeneric.cs b/src/WeihanLi.Common/Logging/LoggerGeneric.cs index da8e4765..116301f5 100644 --- a/src/WeihanLi.Common/Logging/LoggerGeneric.cs +++ b/src/WeihanLi.Common/Logging/LoggerGeneric.cs @@ -20,11 +20,7 @@ internal sealed class GenericLogger : ILogger /// GenericLoggerOptions public GenericLogger(ILoggerFactory factory, IOptions options) { - if (factory == null) - { - throw new ArgumentNullException(nameof(factory)); - } - + Guard.NotNull(factory); var includeGenericParameters = options.Value.FullNamePredict?.Invoke(typeof(T)) == true; _logger = factory.CreateLogger(TypeHelper.GetTypeDisplayName(typeof(T), includeGenericParameters: includeGenericParameters, nestedTypeDelimiter: '.')); } diff --git a/src/WeihanLi.Common/Logging/LoggingBuilder.cs b/src/WeihanLi.Common/Logging/LoggingBuilder.cs index 0296f138..3795b821 100644 --- a/src/WeihanLi.Common/Logging/LoggingBuilder.cs +++ b/src/WeihanLi.Common/Logging/LoggingBuilder.cs @@ -32,9 +32,9 @@ public interface ILogHelperLoggingBuilder internal class LogHelperLoggingBuilder : ILogHelperLoggingBuilder { - internal readonly Dictionary _logHelperProviders = new(); - internal readonly List _logHelperEnrichers = new(); - internal readonly List> _logFilters = new(); + internal readonly Dictionary _logHelperProviders = []; + internal readonly List _logHelperEnrichers = []; + internal readonly List> _logFilters = []; public bool AddProvider(ILogHelperProvider provider) { diff --git a/src/WeihanLi.Common/Logging/LoggingFormatter.cs b/src/WeihanLi.Common/Logging/LoggingFormatter.cs index eb834a1e..75bde1fa 100644 --- a/src/WeihanLi.Common/Logging/LoggingFormatter.cs +++ b/src/WeihanLi.Common/Logging/LoggingFormatter.cs @@ -4,17 +4,11 @@ namespace WeihanLi.Common.Logging; -internal struct FormattedLogValue +internal struct FormattedLogValue(string msg, Dictionary? values) { - public string Msg { get; set; } + public string Msg { get; set; } = msg; - public Dictionary? Values { get; set; } - - public FormattedLogValue(string msg, Dictionary? values) - { - Msg = msg; - Values = values; - } + public Dictionary? Values { get; set; } = values; } internal static class LoggingFormatter @@ -38,9 +32,9 @@ public static FormattedLogValue Format(string msgTemplate, object?[]? values) private class LogValuesFormatter { private const string NullValue = "(null)"; - private static readonly char[] _formatDelimiters = { ':' }; + private static readonly char[] _formatDelimiters = [':']; private readonly string _format; - private readonly List _valueNames = new(); + private readonly List _valueNames = []; public LogValuesFormatter(string format) { @@ -143,7 +137,7 @@ public string FormatWithValues(object?[]? values) } } - return string.Format(CultureInfo.InvariantCulture, _format, values ?? Array.Empty()); + return string.Format(CultureInfo.InvariantCulture, _format, values ?? []); } public IEnumerable> GetValues(object?[] values) @@ -154,7 +148,7 @@ public string FormatWithValues(object?[]? values) valueArray[index] = new KeyValuePair(_valueNames[index], values[index]); } - valueArray[valueArray.Length - 1] = new KeyValuePair("{OriginalFormat}", OriginalFormat); + valueArray[^1] = new KeyValuePair("{OriginalFormat}", OriginalFormat); return valueArray; } diff --git a/src/WeihanLi.Common/Logging/MicrosoftLoggingLogHelperProvider.cs b/src/WeihanLi.Common/Logging/MicrosoftLoggingLogHelperProvider.cs index 8f22faea..c0a294db 100644 --- a/src/WeihanLi.Common/Logging/MicrosoftLoggingLogHelperProvider.cs +++ b/src/WeihanLi.Common/Logging/MicrosoftLoggingLogHelperProvider.cs @@ -2,14 +2,9 @@ namespace WeihanLi.Common.Logging; -internal class MicrosoftLoggingLogHelperProvider : ILogHelperProvider +internal class MicrosoftLoggingLogHelperProvider(ILoggerFactory loggerFactory) : ILogHelperProvider { - private readonly ILoggerFactory _loggerFactory; - - public MicrosoftLoggingLogHelperProvider(ILoggerFactory loggerFactory) - { - _loggerFactory = loggerFactory; - } + private readonly ILoggerFactory _loggerFactory = loggerFactory; public void Log(LogHelperLoggingEvent loggingEvent) { @@ -63,35 +58,18 @@ private static bool LogInternal(ILogger logger, LogHelperLoggingEvent loggingEve private static LogLevel ConvertLogLevel(LogHelperLogLevel logHelperLevel) { - switch (logHelperLevel) + return logHelperLevel switch { - case LogHelperLogLevel.All: - return LogLevel.Debug; - - case LogHelperLogLevel.Info: - return LogLevel.Information; - - case LogHelperLogLevel.Debug: - return LogLevel.Debug; - - case LogHelperLogLevel.Trace: - return LogLevel.Trace; - - case LogHelperLogLevel.Warn: - return LogLevel.Warning; - - case LogHelperLogLevel.Error: - return LogLevel.Error; - - case LogHelperLogLevel.Fatal: - return LogLevel.Critical; - - case LogHelperLogLevel.None: - return LogLevel.None; - - default: - return LogLevel.Warning; - } + LogHelperLogLevel.All => LogLevel.Debug, + LogHelperLogLevel.Info => LogLevel.Information, + LogHelperLogLevel.Debug => LogLevel.Debug, + LogHelperLogLevel.Trace => LogLevel.Trace, + LogHelperLogLevel.Warn => LogLevel.Warning, + LogHelperLogLevel.Error => LogLevel.Error, + LogHelperLogLevel.Fatal => LogLevel.Critical, + LogHelperLogLevel.None => LogLevel.None, + _ => LogLevel.Warning, + }; } } diff --git a/src/WeihanLi.Common/Logging/MicrosoftLoggingLoggerExtensions.cs b/src/WeihanLi.Common/Logging/MicrosoftLoggingLoggerExtensions.cs index a418d550..c38c5db1 100644 --- a/src/WeihanLi.Common/Logging/MicrosoftLoggingLoggerExtensions.cs +++ b/src/WeihanLi.Common/Logging/MicrosoftLoggingLoggerExtensions.cs @@ -8,16 +8,11 @@ namespace Microsoft.Extensions.Logging; [ProviderAlias("Delegate")] -public sealed class DelegateLoggerProvider : ILoggerProvider +public sealed class DelegateLoggerProvider(Action logAction) : ILoggerProvider { - private readonly Action _logAction; + private readonly Action _logAction = logAction; private readonly ConcurrentDictionary _loggers = new(); - public DelegateLoggerProvider(Action logAction) - { - _logAction = logAction; - } - public void Dispose() { _loggers.Clear(); @@ -28,16 +23,10 @@ public ILogger CreateLogger(string categoryName) return _loggers.GetOrAdd(categoryName, category => new DelegateLogger(category, _logAction)); } - private class DelegateLogger : ILogger + private class DelegateLogger(string categoryName, Action logAction) : ILogger { - private readonly string _categoryName; - private readonly Action _logAction; - - public DelegateLogger(string categoryName, Action logAction) - { - _categoryName = categoryName; - _logAction = logAction; - } + private readonly string _categoryName = categoryName; + private readonly Action _logAction = logAction; public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { diff --git a/src/WeihanLi.Common/Models/StringValueDictionary.cs b/src/WeihanLi.Common/Models/StringValueDictionary.cs index 83b5bc2d..3f3723f4 100644 --- a/src/WeihanLi.Common/Models/StringValueDictionary.cs +++ b/src/WeihanLi.Common/Models/StringValueDictionary.cs @@ -7,7 +7,7 @@ namespace WeihanLi.Common.Models; public sealed class StringValueDictionary : IEquatable { - private readonly Dictionary _dictionary = new(); + private readonly Dictionary _dictionary = []; private StringValueDictionary(IDictionary dictionary) { diff --git a/src/WeihanLi.Common/Models/ValidationResult.cs b/src/WeihanLi.Common/Models/ValidationResult.cs index 820e3622..fdec60db 100644 --- a/src/WeihanLi.Common/Models/ValidationResult.cs +++ b/src/WeihanLi.Common/Models/ValidationResult.cs @@ -20,7 +20,7 @@ public interface IValidationResult public sealed class ValidationResult : IValidationResult { - private Dictionary _errors = new(); + private Dictionary _errors = []; /// public bool Valid { get; set; } diff --git a/src/WeihanLi.Common/Services/ITenantProvider.cs b/src/WeihanLi.Common/Services/ITenantProvider.cs index c90d18d9..07120711 100644 --- a/src/WeihanLi.Common/Services/ITenantProvider.cs +++ b/src/WeihanLi.Common/Services/ITenantProvider.cs @@ -1,4 +1,5 @@ -using WeihanLi.Common.Models; +using System.Diagnostics.CodeAnalysis; +using WeihanLi.Common.Models; using WeihanLi.Extensions; namespace WeihanLi.Common.Services; @@ -12,11 +13,13 @@ public interface ITenantProvider public static class TenantIdProviderExtensions { + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? GetTenantId(this ITenantProvider tenantIdProvider, T? defaultValue = default) { return tenantIdProvider.GetTenantId().ToOrDefault(defaultValue); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static bool TryGetTenantId(this ITenantProvider tenantIdProvider, out T? value, T? defaultValue = default) { try diff --git a/src/WeihanLi.Common/Services/IdGenerator.cs b/src/WeihanLi.Common/Services/IdGenerator.cs index f6728d22..0bba2141 100644 --- a/src/WeihanLi.Common/Services/IdGenerator.cs +++ b/src/WeihanLi.Common/Services/IdGenerator.cs @@ -24,14 +24,9 @@ public sealed class GuidIdGenerator : IIdGenerator public string NewId() => Guid.NewGuid().ToString("N"); } -public sealed class SequentialGuidIdGenerator : IIdGenerator +public sealed class SequentialGuidIdGenerator(SequentialGuidType sequentialGuidType) : IIdGenerator { - private readonly SequentialGuidType _sequentialGuidType; - - public SequentialGuidIdGenerator(SequentialGuidType sequentialGuidType) - { - _sequentialGuidType = sequentialGuidType; - } + private readonly SequentialGuidType _sequentialGuidType = sequentialGuidType; public string NewId() => SequentialGuidGenerator.Create(_sequentialGuidType).ToString("N"); } diff --git a/src/WeihanLi.Common/Services/TotpService.cs b/src/WeihanLi.Common/Services/TotpService.cs index 8541d2e0..0a2f4e43 100644 --- a/src/WeihanLi.Common/Services/TotpService.cs +++ b/src/WeihanLi.Common/Services/TotpService.cs @@ -48,14 +48,9 @@ public interface ITotpServiceFactory ITotpService GetService(string? name = null); } -public sealed class TotpServiceFactory : ITotpServiceFactory +public sealed class TotpServiceFactory(IOptionsMonitor optionsMonitor) : ITotpServiceFactory { - private readonly IOptionsMonitor _optionsMonitor; - - public TotpServiceFactory(IOptionsMonitor optionsMonitor) - { - _optionsMonitor = optionsMonitor; - } + private readonly IOptionsMonitor _optionsMonitor = optionsMonitor; public ITotpService GetService(string? name = null) { diff --git a/src/WeihanLi.Common/Services/UserIdProvider.cs b/src/WeihanLi.Common/Services/UserIdProvider.cs index d4a63dcb..4eb33c1b 100644 --- a/src/WeihanLi.Common/Services/UserIdProvider.cs +++ b/src/WeihanLi.Common/Services/UserIdProvider.cs @@ -1,4 +1,5 @@ -using WeihanLi.Extensions; +using System.Diagnostics.CodeAnalysis; +using WeihanLi.Extensions; namespace WeihanLi.Common.Services; @@ -9,11 +10,13 @@ public interface IUserIdProvider public static class UserIdProviderExtensions { + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static T? GetUserId(this IUserIdProvider userIdProvider, T? defaultValue = default) { return userIdProvider.GetUserId().ToOrDefault(defaultValue); } + [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")] public static bool TryGetUserId(this IUserIdProvider userIdProvider, out T? value, T? defaultValue = default) { try diff --git a/src/WeihanLi.Common/Services/Validator.cs b/src/WeihanLi.Common/Services/Validator.cs index c7d92dc4..4fe6f49d 100644 --- a/src/WeihanLi.Common/Services/Validator.cs +++ b/src/WeihanLi.Common/Services/Validator.cs @@ -32,8 +32,8 @@ public ValidationResult Validate(object? value) if (value is null) { validationResult.Valid = false; - validationResult.Errors ??= new Dictionary(); - validationResult.Errors[string.Empty] = new[] { "Value is null" }; + validationResult.Errors ??= []; + validationResult.Errors[string.Empty] = ["Value is null"]; } else { @@ -48,14 +48,9 @@ public ValidationResult Validate(object? value) } } -public sealed class DelegateValidator : IValidator +public sealed class DelegateValidator(Func validateFunc) : IValidator { - private readonly Func _validateFunc; - - public DelegateValidator(Func validateFunc) - { - _validateFunc = Guard.NotNull(validateFunc); - } + private readonly Func _validateFunc = Guard.NotNull(validateFunc); public ValidationResult Validate(object? value) { diff --git a/src/WeihanLi.Common/Template/DefaultRenderMiddleware.cs b/src/WeihanLi.Common/Template/DefaultRenderMiddleware.cs index 4ef70a25..11bd4f98 100644 --- a/src/WeihanLi.Common/Template/DefaultRenderMiddleware.cs +++ b/src/WeihanLi.Common/Template/DefaultRenderMiddleware.cs @@ -1,23 +1,12 @@ // Copyright (c) Weihan Li. All rights reserved. // Licensed under the Apache license. -using WeihanLi.Extensions; - namespace WeihanLi.Common.Template; internal sealed class DefaultRenderMiddleware : IRenderMiddleware { public async Task InvokeAsync(TemplateRenderContext context, Func next) { - if (context.Text.IsNullOrWhiteSpace()) return; - await next(context); - - context.RenderedText = context.Text; - foreach (var parameter in context.Parameters) - { - context.RenderedText = - context.RenderedText.Replace($"{{{{{parameter.Key}}}}}", parameter.Value?.ToString()); - } } } diff --git a/src/WeihanLi.Common/Template/DefaultTemplateRenderer.cs b/src/WeihanLi.Common/Template/DefaultTemplateRenderer.cs index 98dd6002..82a96fdf 100644 --- a/src/WeihanLi.Common/Template/DefaultTemplateRenderer.cs +++ b/src/WeihanLi.Common/Template/DefaultTemplateRenderer.cs @@ -9,8 +9,17 @@ internal sealed class DefaultTemplateRenderer(Func { public async Task RenderAsync(TemplateRenderContext context, object? globals) { + if (context.Text.IsNullOrWhiteSpace() || context.Variables.IsNullOrEmpty()) + return context.Text; + context.Parameters = globals.ParseParamDictionary(); await renderFunc.Invoke(context).ConfigureAwait(false); + foreach (var parameter in context.Parameters) + { + context.RenderedText = context.RenderedText.Replace( + $"{{{{{parameter.Key}}}}}", parameter.Value?.ToString() + ); + } return context.RenderedText; } } diff --git a/src/WeihanLi.Common/Template/DependencyInjectionExtensions.cs b/src/WeihanLi.Common/Template/DependencyInjectionExtensions.cs index 961f2365..0b9301d0 100644 --- a/src/WeihanLi.Common/Template/DependencyInjectionExtensions.cs +++ b/src/WeihanLi.Common/Template/DependencyInjectionExtensions.cs @@ -11,11 +11,11 @@ namespace WeihanLi.Common.Template; public static class DependencyInjectionExtensions { - public static IServiceCollection AddTemplating(this IServiceCollection services, Action? optionsConfigure = null) + public static IServiceCollection AddTemplateEngine(this IServiceCollection services, Action? optionsConfigure = null) { Guard.NotNull(services); if (services.Any(x => x.ServiceType == typeof(ITemplateEngine))) - throw new InvalidOperationException("Templating services had been registered"); + throw new InvalidOperationException("Template engine services had been registered"); if (optionsConfigure != null) services.AddOptions().Configure(optionsConfigure); diff --git a/src/WeihanLi.Common/Template/TemplateRenderContext.cs b/src/WeihanLi.Common/Template/TemplateRenderContext.cs index 254c7e74..09032696 100644 --- a/src/WeihanLi.Common/Template/TemplateRenderContext.cs +++ b/src/WeihanLi.Common/Template/TemplateRenderContext.cs @@ -4,18 +4,11 @@ using WeihanLi.Common.Abstractions; namespace WeihanLi.Common.Template; -public sealed class TemplateRenderContext : IProperties +public sealed class TemplateRenderContext(string text, HashSet variables) : IProperties { - public TemplateRenderContext(string text, HashSet variables) - { - Text = text; - Variables = variables; - RenderedText = string.Empty; - } - - public string Text { get; } - public HashSet Variables { get; } - public string RenderedText { get; set; } + public string Text { get; } = text; + public HashSet Variables { get; } = variables; + public string RenderedText { get; set; } = text; public IDictionary Parameters { get; set; } = new Dictionary(); public IDictionary Properties { get; } = new Dictionary(); } diff --git a/test/WeihanLi.Common.Test/ExtensionsTest/CoreExtensionTest.cs b/test/WeihanLi.Common.Test/ExtensionsTest/CoreExtensionTest.cs index 030fc1ea..b5803c87 100644 --- a/test/WeihanLi.Common.Test/ExtensionsTest/CoreExtensionTest.cs +++ b/test/WeihanLi.Common.Test/ExtensionsTest/CoreExtensionTest.cs @@ -87,7 +87,7 @@ public void SafeSubstring() Assert.Equal("bcdefg", str.SafeSubstring(1, 20)); Assert.Equal("", str.SafeSubstring(10, 20)); - Assert.Equal(str.Substring(str.Length), str.SafeSubstring(str.Length)); + Assert.Equal(str[str.Length..], str.SafeSubstring(str.Length)); Assert.Equal("", str.SafeSubstring(10)); } diff --git a/test/WeihanLi.Common.Test/ExtensionsTest/ServiceCollectionExtensionTest.cs b/test/WeihanLi.Common.Test/ExtensionsTest/ServiceCollectionExtensionTest.cs index 3f5aeb84..2f66996f 100644 --- a/test/WeihanLi.Common.Test/ExtensionsTest/ServiceCollectionExtensionTest.cs +++ b/test/WeihanLi.Common.Test/ExtensionsTest/ServiceCollectionExtensionTest.cs @@ -49,13 +49,9 @@ public void Execute() } } - private sealed class JobDecorator : IJob + private sealed class JobDecorator(IJob job) : IJob { - private readonly IJob _job; - public JobDecorator(IJob job) - { - _job = job; - } + private readonly IJob _job = job; public string Name => $"??? {_job.Name}"; @@ -79,14 +75,9 @@ private class DefaultValueProvider : IValueProvider return default; } } - private sealed class ValueProviderDecorator : IValueProvider + private sealed class ValueProviderDecorator(IValueProvider valueProvider) : IValueProvider { - private readonly IValueProvider _valueProvider; - - public ValueProviderDecorator(IValueProvider valueProvider) - { - _valueProvider = valueProvider; - } + private readonly IValueProvider _valueProvider = valueProvider; public int Counter { get; private set; } diff --git a/test/WeihanLi.Common.Test/ExtensionsTest/StringExtensionTest.cs b/test/WeihanLi.Common.Test/ExtensionsTest/StringExtensionTest.cs index d67da244..76e238e6 100644 --- a/test/WeihanLi.Common.Test/ExtensionsTest/StringExtensionTest.cs +++ b/test/WeihanLi.Common.Test/ExtensionsTest/StringExtensionTest.cs @@ -58,7 +58,7 @@ public void StringGetValue(string? value, string defaultValue) [InlineData(null, null)] public void TrimStart(string? value, string? start) { - var expected = start.IsNotNullOrEmpty() && value?.StartsWith(start!) == true ? value.Substring(start!.Length) : value; + var expected = start.IsNotNullOrEmpty() && value?.StartsWith(start!) == true ? value[start!.Length..] : value; Assert.Equal(expected, value!.TrimStart(start!)); } @@ -117,11 +117,11 @@ public void SplitArray() Assert.True(array.SequenceEqual(Enumerable.Range(1, count))); str = Enumerable.Range(1, count).StringJoin(";"); - array = str.SplitArray(new[] { ';' }); + array = str.SplitArray([';']); Assert.Equal(count, array.Length); Assert.True(array.SequenceEqual(Enumerable.Range(1, count))); - var array1 = str.SplitArray(new[] { ';' }); + var array1 = str.SplitArray([';']); Assert.Equal(count, array1.Length); Assert.True(array1.Select(x => x.GetValueOrDefault()).SequenceEqual(Enumerable.Range(1, count))); } diff --git a/test/WeihanLi.Common.Test/ModelsTest/StringValueDictionaryTest.cs b/test/WeihanLi.Common.Test/ModelsTest/StringValueDictionaryTest.cs index 98e942e6..b8d08f96 100644 --- a/test/WeihanLi.Common.Test/ModelsTest/StringValueDictionaryTest.cs +++ b/test/WeihanLi.Common.Test/ModelsTest/StringValueDictionaryTest.cs @@ -31,9 +31,11 @@ public void DistinctTest() { "Id", 1 }, { "Name", "Tom" }, }); - var set = new HashSet(); - set.Add(dic1); - set.Add(dic2); + var set = new HashSet + { + dic1, + dic2 + }; Assert.Single(set); } diff --git a/test/WeihanLi.Common.Test/ServicesTest/TotpServiceTest.cs b/test/WeihanLi.Common.Test/ServicesTest/TotpServiceTest.cs index 6d87dec8..8c0fbd90 100644 --- a/test/WeihanLi.Common.Test/ServicesTest/TotpServiceTest.cs +++ b/test/WeihanLi.Common.Test/ServicesTest/TotpServiceTest.cs @@ -29,8 +29,8 @@ public void GetCodeWithTtlTest() { const string bizToken = "Test1234"; var totpService = new TotpService(new TotpOptions()); - var code = totpService.GetCodeWithTtl(bizToken); - Assert.NotEmpty(code.Code); - Assert.True(code.Ttl >= 1); + var (Code, Ttl) = totpService.GetCodeWithTtl(bizToken); + Assert.NotEmpty(Code); + Assert.True(Ttl >= 1); } }