diff --git a/.github/workflows/codecov.yml b/.github/workflows/codecov.yml new file mode 100644 index 0000000..688b5ec --- /dev/null +++ b/.github/workflows/codecov.yml @@ -0,0 +1,25 @@ +name: CodeCov + +on: + push: + branches: + - "main" + paths-ignore: + - ".*/**" + - "**/*.md" + pull_request: + branches: + - "main" + paths-ignore: + - ".*/**" + - "**/*.md" + + workflow_dispatch: + +jobs: + codecov: + runs-on: ubuntu-latest + + steps: + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v3 diff --git a/Common.BasicHelper.Samples/Common.BasicHelper.Samples.csproj b/Common.BasicHelper.Samples/Common.BasicHelper.Samples.csproj new file mode 100644 index 0000000..04c0c6c --- /dev/null +++ b/Common.BasicHelper.Samples/Common.BasicHelper.Samples.csproj @@ -0,0 +1,18 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + diff --git a/Common.BasicHelper.Samples/Program.cs b/Common.BasicHelper.Samples/Program.cs new file mode 100644 index 0000000..53d1139 --- /dev/null +++ b/Common.BasicHelper.Samples/Program.cs @@ -0,0 +1,41 @@ +using Common.BasicHelper.Core.Shell; +using Common.BasicHelper.Utils.Extensions; +using System.Web; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle +builder.Services.AddEndpointsApiExplorer(); +builder.Services.AddSwaggerGen(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + +app.UseHttpsRedirection(); + +app.MapGet("/Utils/Extensions/StringHelper/ExecuteAsCommand/{cmd}.{args?}", + (string cmd, string? args) => cmd.ExecuteAsCommand( + args == "," || args == "{args}" || args.IsNullOrWhiteSpace() + ? null : HttpUtility.UrlDecode(args) + ) +) +.WithName("ExecuteAsCommand") +.WithOpenApi(); + +app.MapGet("/Utils/Extensions/StringHelper/ExecuteAsCommandAsync/{cmd}.{args?}", + async (string cmd, string? args) => await cmd.ExecuteAsCommandAsync( + args == "," || args == "{args}" || args.IsNullOrWhiteSpace() + ? null : HttpUtility.UrlDecode(args) + ) +) +.WithName("ExecuteAsCommandAsync") +.WithOpenApi(); + +app.Run(); diff --git a/Common.BasicHelper.Samples/Properties/launchSettings.json b/Common.BasicHelper.Samples/Properties/launchSettings.json new file mode 100644 index 0000000..2bd856d --- /dev/null +++ b/Common.BasicHelper.Samples/Properties/launchSettings.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://json.schemastore.org/launchsettings.json", + "iisSettings": { + "windowsAuthentication": false, + "anonymousAuthentication": true, + "iisExpress": { + "applicationUrl": "http://localhost:40529", + "sslPort": 44396 + } + }, + "profiles": { + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "http://localhost:5077", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": false, + "launchUrl": "swagger", + "applicationUrl": "https://localhost:7219;http://localhost:5077", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + }, + "IIS Express": { + "commandName": "IISExpress", + "launchBrowser": true, + "launchUrl": "swagger", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + } + } + } +} diff --git a/Common.BasicHelper.Samples/Utils/Extensions/StringHelper.cs b/Common.BasicHelper.Samples/Utils/Extensions/StringHelper.cs new file mode 100644 index 0000000..c65bb28 --- /dev/null +++ b/Common.BasicHelper.Samples/Utils/Extensions/StringHelper.cs @@ -0,0 +1,7 @@ +namespace Common.BasicHelper.Samples.Utils.Extensions; + +public static class StringHelper +{ + + +} diff --git a/Common.BasicHelper.Samples/appsettings.Development.json b/Common.BasicHelper.Samples/appsettings.Development.json new file mode 100644 index 0000000..0c208ae --- /dev/null +++ b/Common.BasicHelper.Samples/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/Common.BasicHelper.Samples/appsettings.json b/Common.BasicHelper.Samples/appsettings.json new file mode 100644 index 0000000..10f68b8 --- /dev/null +++ b/Common.BasicHelper.Samples/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + }, + "AllowedHosts": "*" +} diff --git a/Common.BasicHelper.Test/Common.BasicHelper.Test.csproj b/Common.BasicHelper.Test/Common.BasicHelper.Test.csproj index 029c504..3b177bf 100644 --- a/Common.BasicHelper.Test/Common.BasicHelper.Test.csproj +++ b/Common.BasicHelper.Test/Common.BasicHelper.Test.csproj @@ -1,7 +1,7 @@ - net6.0 + net7.0 enable enable diff --git a/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs b/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs new file mode 100644 index 0000000..9f8017f --- /dev/null +++ b/Common.BasicHelper.Test/Core/Shell/CommandsExecutor_Tests.cs @@ -0,0 +1,17 @@ +namespace Common.BasicHelper.Core.Shell; + +[TestClass] +public class CommandsExecutor_Tests +{ + [TestMethod] + public void Test_ExecuteAsCommand() + { + Console.WriteLine("help".ExecuteAsCommand()); + } + + [TestMethod] + public async Task Test_ExecuteAsCommandAsync() + { + Console.WriteLine(await "help".ExecuteAsCommandAsync()); + } +} diff --git a/Common.BasicHelper.Test/Core/Shell/EnvironmentHelper_Tests.cs b/Common.BasicHelper.Test/Core/Shell/EnvironmentHelper_Tests.cs new file mode 100644 index 0000000..549259a --- /dev/null +++ b/Common.BasicHelper.Test/Core/Shell/EnvironmentHelper_Tests.cs @@ -0,0 +1,5 @@ +namespace Common.BasicHelper.Core.Shell; + +public class EnvironmentHelper_Tests +{ +} diff --git a/Common.BasicHelper.Test/Core/Shell/Test_CommandsExecutor.cs b/Common.BasicHelper.Test/Core/Shell/Test_CommandsExecutor.cs deleted file mode 100644 index cb209bc..0000000 --- a/Common.BasicHelper.Test/Core/Shell/Test_CommandsExecutor.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Common.BasicHelper.Core.Shell; - -namespace Common.BasicHelper.Test.Core.Shell; - -[TestClass] -public class Test_CommandsExecutor -{ - [TestMethod] - public void Test_Command() - { - Console.WriteLine("help".ExecuteAsCommand()); - } -} diff --git a/Common.BasicHelper.Test/Core/Shell/Test_EnvironmentHelper.cs b/Common.BasicHelper.Test/Core/Shell/Test_EnvironmentHelper.cs deleted file mode 100644 index ffe1e69..0000000 --- a/Common.BasicHelper.Test/Core/Shell/Test_EnvironmentHelper.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Common.BasicHelper.Test.Core.Shell; - -internal class Test_EnvironmentHelper -{ -} diff --git a/Common.BasicHelper.Test/Graphics/Screen/Resolution_Tests.cs b/Common.BasicHelper.Test/Graphics/Screen/Resolution_Tests.cs new file mode 100644 index 0000000..0814e9b --- /dev/null +++ b/Common.BasicHelper.Test/Graphics/Screen/Resolution_Tests.cs @@ -0,0 +1,24 @@ +namespace Common.BasicHelper.Graphics.Screen; + +[TestClass] +public class Resolution_Tests +{ + [TestMethod()] + public void Test_Suggest() + { + foreach (var item in Resolution.resolutions) + { + var tarRes = Resolution.Suggest( + Resolution.Parse("2560x1440"), + Resolution.Parse("1280x720"), + item + ).Integerization(); + + Console.WriteLine( + "" + + $"{item} ({item.Description})\r\n" + + $"\t{tarRes}" + ); + } + } +} diff --git a/Common.BasicHelper.Test/Graphics/Screen/Test_Resolution.cs b/Common.BasicHelper.Test/Graphics/Screen/Test_Resolution.cs deleted file mode 100644 index d1b83c8..0000000 --- a/Common.BasicHelper.Test/Graphics/Screen/Test_Resolution.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Common.BasicHelper.Graphics.Screen; - -namespace Common.BasicHelper.Test.Graphics.Screen; - -[TestClass] -public class Test_Resolution -{ - [TestMethod] - public void Test_SuggestResolution() - { - foreach (var item in Resolution.resolutions) - { - Resolution tarRes = Resolution.Suggest(Resolution.Parse("2560x1440"), - Resolution.Parse("1280x720"), item).Integerization(); - Console.WriteLine($"{item}\r\n\t{tarRes}"); - } - } -} diff --git a/Common.BasicHelper.Test/IO/FileHelper_Tests.cs b/Common.BasicHelper.Test/IO/FileHelper_Tests.cs new file mode 100644 index 0000000..874e042 --- /dev/null +++ b/Common.BasicHelper.Test/IO/FileHelper_Tests.cs @@ -0,0 +1,190 @@ +using Common.BasicHelper.Utils.Extensions; +using System.Text; + +namespace Common.BasicHelper.IO; + +[TestClass()] +public class FileHelper_Tests +{ + [TestMethod()] + public void Test_WriteIn() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteIn(file, "Test"); + + var read = File.ReadAllText(file); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } + + [TestMethod()] + public void Test_Append() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteIn(file, "Test"); + + FileHelper.Append(file, "Test"); + + var read = File.ReadAllText(file); + + File.Delete(file); + + Assert.AreEqual(read, $"Test{Environment.NewLine}Test"); + } + + [TestMethod()] + public void Test_WriteBytesTo() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteBytesTo(file, Encoding.UTF8.GetBytes("Test")); + + var read = File.ReadAllText(file); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } + + [TestMethod()] + public void Test_WriteBytesToFile() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteBytesToFile(file, Encoding.UTF8.GetBytes("Test")); + + var read = File.ReadAllText(file); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } + + [TestMethod()] + public void Test_ReadAll() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteIn(file, "Test"); + + var read = FileHelper.ReadAll(file); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } + + [TestMethod()] + public async Task Test_ReadAllAsync() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteIn(file, "Test"); + + var read = await FileHelper.ReadAllAsync(file); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } + + [TestMethod()] + public void Test_ReadAllBytes() + { + var file = Path.GetTempFileName(); + + file.Print(); + + var bytes = Encoding.UTF8.GetBytes("Test"); + + FileHelper.WriteBytesTo(file, bytes); + + var read = FileHelper.ReadAllBytes(file); + + File.Delete(file); + + Assert.AreEqual(read.LongLength, bytes.LongLength); + + for (int i = 0; i < read.LongLength; ++i) + Assert.AreEqual(read[i], bytes[i]); + } + + [TestMethod()] + public void Test_FileToByte() + { + var file = Path.GetTempFileName(); + + file.Print(); + + var bytes = Encoding.UTF8.GetBytes("Test"); + + FileHelper.WriteBytesTo(file, bytes); + + var read = FileHelper.FileToBytes(file); + + File.Delete(file); + + Assert.AreEqual(read.LongLength, bytes.LongLength); + + for (int i = 0; i < read.LongLength; ++i) + Assert.AreEqual(read[i], bytes[i]); + } + + [TestMethod()] + public void Test_ByteToFile() + { + var file = Path.GetTempFileName(); + + file.Print(); + + var bytes = Encoding.UTF8.GetBytes("Test"); + + FileHelper.ByteToFile(bytes, file); + + var read = FileHelper.ReadAllBytes(file); + + File.Delete(file); + + Assert.AreEqual(read.LongLength, bytes.LongLength); + + for (int i = 0; i < read.LongLength; ++i) + Assert.AreEqual(read[i], bytes[i]); + } + + [TestMethod()] + public void Test_CreateFile() + { + var file = Path.GetTempFileName(); + + file.Print(); + + var bytes = Encoding.UTF8.GetBytes("Test"); + + FileHelper.CreateFile(bytes, file); + + var read = FileHelper.ReadAllBytes(file); + + File.Delete(file); + + Assert.AreEqual(read.LongLength, bytes.LongLength); + + for (int i = 0; i < read.LongLength; ++i) + Assert.AreEqual(read[i], bytes[i]); + } +} diff --git a/Common.BasicHelper.Test/Math/Equation_Tests.cs b/Common.BasicHelper.Test/Math/Equation_Tests.cs new file mode 100644 index 0000000..2d04c9b --- /dev/null +++ b/Common.BasicHelper.Test/Math/Equation_Tests.cs @@ -0,0 +1,40 @@ +using Common.BasicHelper.Utils.Extensions; + +namespace Common.BasicHelper.Math; + +[TestClass()] +public class Equation_Tests +{ + [TestMethod()] + public void Test_SolveEquation() + { + Assert.AreEqual + ( + Equation.SolveEquation(3, 4, 55, 6, -2, 10).Print(), + "5, 10" + ); + + Assert.AreEqual + ( + Equation.SolveEquation + ( + 3, 5, -3, 8, + 5, -1, 4, 30, + 2, 3, -1, 10 + ).Print(), + "2, 4, 6" + ); + + Assert.AreEqual + ( + Equation.SolveEquation + ( + 2, 3, 5, 7, 31, + 4, 5, 7, 11, 61, + 3, 2, 4, 5, 26, + 1, 1, 2, 3, 13 + ).Print(), + "5, 7, -7, 5" + ); + } +} diff --git a/Common.BasicHelper.Test/Math/Standard_Tests.cs b/Common.BasicHelper.Test/Math/Standard_Tests.cs new file mode 100644 index 0000000..90708d0 --- /dev/null +++ b/Common.BasicHelper.Test/Math/Standard_Tests.cs @@ -0,0 +1,15 @@ +using Common.BasicHelper.Utils.Extensions; + +namespace Common.BasicHelper.Math; + +[TestClass()] +public class Standard_Tests +{ + [TestMethod()] + public void Test_GetPosition() + { + Standard.GetPosition(2468, 3).Print(); + + 2468.GetPosition(4).Print(); + } +} diff --git a/Common.BasicHelper.Test/Math/Tricks_Tests.cs b/Common.BasicHelper.Test/Math/Tricks_Tests.cs new file mode 100644 index 0000000..d6eca3d --- /dev/null +++ b/Common.BasicHelper.Test/Math/Tricks_Tests.cs @@ -0,0 +1,17 @@ +namespace Common.BasicHelper.Math; + +[TestClass()] +public class Tricks_Tests +{ + [TestMethod()] + public void Test_GetMultiplicationTable() + { + Console.WriteLine(Tricks.GetMultiplicationTable(1, 9)); + + Console.WriteLine(Tricks.GetMultiplicationTable(9, 1, false)); + + Console.WriteLine(1.GetMultiplicationTableTo(9)); + + Console.WriteLine(9.GetMultiplicationTableTo(1, false)); + } +} diff --git a/Common.BasicHelper.Test/Network/NetUtils_Tests.cs b/Common.BasicHelper.Test/Network/NetUtils_Tests.cs new file mode 100644 index 0000000..a23206f --- /dev/null +++ b/Common.BasicHelper.Test/Network/NetUtils_Tests.cs @@ -0,0 +1,34 @@ +namespace Common.BasicHelper.Network; + +[TestClass] +public class NetUtils_Tests +{ + private const string testDownloadFilePath = "https://www.baidu.com/index.html"; + + [TestMethod] + public void Test_IsWebConected() + { + Assert.IsTrue(NetUtils.IsWebConected("localhost", 3)); + Assert.IsFalse(NetUtils.IsWebConected("192.168.255.255", 3)); + } + + [TestMethod] + public void Test_DownloadFile() + { + var path = Path.GetFullPath($"{Path.GetTempPath()}/test_downloadFile.txt"); + + NetUtils.DownloadFile(testDownloadFilePath, path); + + File.Delete(path); + } + + [TestMethod] + public void Test_WebDownloadFile() + { + var path = Path.GetFullPath($"{Path.GetTempPath()}/test_webDownloadFile.txt"); + + NetUtils.WebDownloadFile(testDownloadFilePath, path); + + File.Delete(path); + } +} \ No newline at end of file diff --git a/Common.BasicHelper.Test/Time/NTP_Tests.cs b/Common.BasicHelper.Test/Time/NTP_Tests.cs new file mode 100644 index 0000000..02e5705 --- /dev/null +++ b/Common.BasicHelper.Test/Time/NTP_Tests.cs @@ -0,0 +1,123 @@ +using System.Text; + +namespace Common.BasicHelper.Time; + +[TestClass] +public class NTP_Tests +{ + private static double GetOffsetsMillisecondsInRandomWay(bool useTimeSpan = false, bool print = true) + { + var random = new Random(); + + // 发送时网络延迟 + var networkInterval_1 = TimeSpan.FromMilliseconds(random.Next(1, 1000)); + + // 接收时网络延迟 + var networkInterval_2 = TimeSpan.FromMilliseconds(random.Next(1, 1000)); + + // 真实时间差 + var actualOffset = TimeSpan.FromSeconds(random.Next(1, 100)); + + // 本地发送时时间戳 + var localSend = DateTime.Now; + + // 远程接收时时间戳 + var remoteReceive = localSend + networkInterval_1 + actualOffset; + + // 远程发送时时间戳 + var remoteSend = remoteReceive; + + // 本地接收时时间戳 + var localReceive = remoteSend + networkInterval_2; + + // 计算时间差毫秒数 + var calculateOffsetMilliseconds = NTP + .GetOffset(localSend, remoteReceive, remoteSend, localReceive); + + // 计算时间差 + var calculateOffset = useTimeSpan + ? NTP.GetOffsetTimeSpan(localSend, remoteReceive, remoteSend, localReceive) + : TimeSpan.FromMilliseconds(calculateOffsetMilliseconds); + + // 计算时间差与真实时间差的差值 + var offsetsDelta = calculateOffset - actualOffset; + + // 计算时间差与真实时间差的差值的毫秒数的绝对值 + var offsetsDeltaMilliseconds = System.Math.Abs(offsetsDelta.TotalMilliseconds); + + if (print) + { + static string ToTotalTimeString(DateTime time) => time.ToString("O"); + + var sb = new StringBuilder(); + + sb.AppendLine($"Local sending time: {ToTotalTimeString(localSend)}"); + sb.AppendLine($"Network delayed: {networkInterval_1.TotalMilliseconds} ms"); + sb.AppendLine($"Remote receiving time: {ToTotalTimeString(remoteReceive)}"); + sb.AppendLine($"Remote sending time: {ToTotalTimeString(remoteSend)}"); + sb.AppendLine($"Network delayed: {networkInterval_2.TotalMilliseconds} ms"); + sb.AppendLine($"Local receiving time: {ToTotalTimeString(localReceive)}"); + sb.AppendLine(); + sb.AppendLine($"Actual offset: {actualOffset}"); + sb.AppendLine($"Calculate offset: {calculateOffset}"); + sb.AppendLine($"Delta of two offsets: {offsetsDeltaMilliseconds} ms"); + + Console.WriteLine(sb.ToString()); + } + + return offsetsDeltaMilliseconds; + } + + [TestMethod] + public void Test_GetOffset() + { + var offsetsDeltaMilliseconds = GetOffsetsMillisecondsInRandomWay(); + + Assert.IsTrue(offsetsDeltaMilliseconds < 1200); + } + + [TestMethod] + public void Test_GetOffsetTimeSpan() + { + var offsetsDeltaMilliseconds = GetOffsetsMillisecondsInRandomWay( + useTimeSpan: true + ); + + Assert.IsTrue(offsetsDeltaMilliseconds < 1200); + } + + [TestMethod] + public void BenchMark_GetOffset() + { + var totalOffsetsDeltaMilliseconds = 0.0; + + var tasksCount = 1000; + + //var addLock = new object(); + + //var tasks = new List(); + + //foreach (var task in Enumerable.Range(1, tasksCount)) + // tasks.Add(new Task(() => + // { + // var offsetsDeltaMilliseconds = GetOffsetsMillisecondsInRandomWay(); + + // lock (addLock) + // { + // totalOffsetsDeltaMilliseconds += offsetsDeltaMilliseconds; + // } + // })); + + //await Task.WhenAll(tasks); + + foreach (var task in Enumerable.Range(1, tasksCount)) + totalOffsetsDeltaMilliseconds += GetOffsetsMillisecondsInRandomWay(print: false); + + var averageMilliseconds = totalOffsetsDeltaMilliseconds / tasksCount; + + Console.WriteLine($"Tasks count: {tasksCount}"); + Console.WriteLine($"Average offsets delta: {averageMilliseconds} ms"); + + Assert.IsTrue(averageMilliseconds < 1200); + } +} diff --git a/Common.BasicHelper.Test/Utils/COID_Helper_Tests.cs b/Common.BasicHelper.Test/Utils/COID_Helper_Tests.cs new file mode 100644 index 0000000..9f3b18e --- /dev/null +++ b/Common.BasicHelper.Test/Utils/COID_Helper_Tests.cs @@ -0,0 +1,49 @@ +namespace Common.BasicHelper.Utils; + +[TestClass] +public class COID_Helper_Tests +{ + [TestMethod] + public void Test_Random_COID_Generate() + { + for (int i = 0; i < 10; ++i) + Console.WriteLine(COID_Helper.Random_COID_Generate().GetString()); + } + + [TestMethod] + public void Test_Build_COID() + { + _ = COID_Helper.Build_COID("98KTD-N4GFV-J1RQK-E7CWJ-F9NTJ"); + + Assert.ThrowsException( + () => COID_Helper.Build_COID("98KTD-N4GFV-J1RQK-E7CWJ") + ); + } + + [TestMethod] + public void Test_Build_COID_Part() + { + var coid_part = COID_Helper.Build_COID_Part("98KTD"); + + Assert.AreEqual(coid_part.ToString(), "98KTD"); + + coid_part = new COID_Part() + { + A = 'A', + B = 'B', + C = 'C', + D = 'D', + E = 'E', + }; + + Assert.AreEqual(coid_part.ToString(), "ABCDE"); + + Assert.ThrowsException( + () => COID_Helper.Build_COID_Part("1234") + ); + + Assert.ThrowsException( + () => COID_Helper.Build_COID_Part("1#5$9") + ); + } +} diff --git a/Common.BasicHelper.Test/Utils/COID_Tests.cs b/Common.BasicHelper.Test/Utils/COID_Tests.cs new file mode 100644 index 0000000..d60f9a8 --- /dev/null +++ b/Common.BasicHelper.Test/Utils/COID_Tests.cs @@ -0,0 +1,23 @@ +namespace Common.BasicHelper.Utils; + +[TestClass] +public class COID_Tests +{ + [TestMethod] + public void Test_Equals() + { + var coid_a = COID_Helper.Build_COID("98KTD-N4GFV-J1RQK-E7CWJ-F9NTJ"); + var coid_b = COID_Helper.Build_COID("98KTD-N4GFV-J1RQK-E7CWJ-F9NTJ"); + + Assert.AreEqual(coid_a, coid_b); + } + + [TestMethod] + public void Test_GetHashCode() + { + var coid_a = COID_Helper.Build_COID("98KTD-N4GFV-J1RQK-E7CWJ-F9NTJ"); + var coid_b = COID_Helper.Build_COID("98KTD-N4GFV-J1RQK-E7CWJ-F9NTJ"); + + Assert.AreEqual(coid_a.GetHashCode(), coid_b.GetHashCode()); + } +} \ No newline at end of file diff --git a/Common.BasicHelper.Test/Utils/Extensions/CleanHelper_Tests.cs b/Common.BasicHelper.Test/Utils/Extensions/CleanHelper_Tests.cs new file mode 100644 index 0000000..8d13811 --- /dev/null +++ b/Common.BasicHelper.Test/Utils/Extensions/CleanHelper_Tests.cs @@ -0,0 +1,43 @@ +using System.Diagnostics; +using System.IO.Pipes; +using System.Net.Sockets; + +namespace Common.BasicHelper.Utils.Extensions; + +[TestClass] +public class CleanHelper_Tests +{ + [TestMethod] + public void Test_CloseAndDispose() + { + // Arrange + var memoryStream = new MemoryStream(); + var namedPipeServerStream = new NamedPipeServerStream("testpipe", + PipeDirection.InOut); + var binaryReader = new BinaryReader(memoryStream); + var binaryWriter = new BinaryWriter(memoryStream); + var streamReader = new StreamReader(memoryStream); + var streamWriter = new StreamWriter(memoryStream); + var process = new Process(); + var socket = new Socket(SocketType.Stream, ProtocolType.Tcp); + + // Act + namedPipeServerStream.CloseAndDispose(); + binaryReader.CloseAndDispose(); + binaryWriter.CloseAndDispose(); + streamReader.CloseAndDispose(); + streamWriter.CloseAndDispose(); + process.CloseAndDispose(); + socket.CloseAndDispose(); + + memoryStream.CloseAndDispose(); + + // Assert + Assert.IsTrue(namedPipeServerStream.IsConnected == false); + Assert.IsTrue(binaryReader.BaseStream.CanRead == false); + Assert.IsTrue(binaryWriter.BaseStream.CanWrite == false); + Assert.IsTrue(streamReader.BaseStream.CanRead == false); + Assert.IsTrue(streamWriter.BaseStream.CanWrite == false); + Assert.IsTrue(socket.Connected == false); + } +} \ No newline at end of file diff --git a/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs b/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs new file mode 100644 index 0000000..0a1713e --- /dev/null +++ b/Common.BasicHelper.Test/Utils/Extensions/Dumpper_Tests.cs @@ -0,0 +1,60 @@ +using System.Net.NetworkInformation; + +namespace Common.BasicHelper.Utils.Extensions; + +[TestClass()] +public class Dumpper_Tests +{ + [TestMethod()] + public void Test_Dump() + { + new Queue() + .Push(null) + .Push(1) + .Dump() + ; + + var interfaces = NetworkInterface.GetAllNetworkInterfaces(); + foreach (var iface in interfaces) + iface.Dump(); + } + + [TestMethod()] + public void Test_Dump2Lines() + { + new Queue() + .Push(null) + .Push(1) + .Dump2Lines() + ; + + var interfaces = NetworkInterface.GetAllNetworkInterfaces(); + foreach (var iface in interfaces) + iface.Dump2Lines(); + } + + [TestMethod()] + public void Test_Print() + { + Assert.AreEqual("Test".Print(), "Test"); + + Assert.AreEqual(24523.Print(), "24523"); + + Assert.AreEqual(new List() + { + 1, 2, 3 + }.Print(), "1, 2, 3"); + + Assert.AreEqual(new string[3] + { + "12", + "34", + "56" + }.Print(), """ + 12 + 34 + 56 + + """); + } +} diff --git a/Common.BasicHelper.Test/Utils/Extensions/ListHelper_Tests.cs b/Common.BasicHelper.Test/Utils/Extensions/ListHelper_Tests.cs new file mode 100644 index 0000000..5ff6170 --- /dev/null +++ b/Common.BasicHelper.Test/Utils/Extensions/ListHelper_Tests.cs @@ -0,0 +1,27 @@ +namespace Common.BasicHelper.Utils.Extensions; + +[TestClass()] +public class ListHelper_Tests +{ + [TestMethod()] + public void Test_ToCustomString() + { + Assert.AreEqual + ( + new List() + { + 1, 2, 3, 4, 5, 6, 7, + }.ToCustomString().Print(), + "1,2,3,4,5,6,7" + ); + + Assert.AreEqual + ( + new List() + { + 1, 2, 3, 4, 5, 6, 7, + }.ToCustomString(cutEnding: false).Print(), + "1,2,3,4,5,6,7," + ); + } +} diff --git a/Common.BasicHelper.Test/Utils/Extensions/QueueHelper_Tests.cs b/Common.BasicHelper.Test/Utils/Extensions/QueueHelper_Tests.cs new file mode 100644 index 0000000..09718ee --- /dev/null +++ b/Common.BasicHelper.Test/Utils/Extensions/QueueHelper_Tests.cs @@ -0,0 +1,107 @@ +using System.Text; + +namespace Common.BasicHelper.Utils.Extensions; + +[TestClass] +public class QueueHelper_Tests +{ + [TestMethod] + public void Test_QueueExtensions() + { + var queue = new Queue() + .Push(1) + .Push(2) + .Push(3) + .Push(4) + .Push(5) + .Push(6) + .Pop() + ; + while (queue.IsNotEmpty()) + { + queue = queue.ForEach(x => ++x); + queue = queue.Pop(); + } + Assert.AreEqual(0, queue.Count); + } + + [TestMethod] + public void Test_DumpQueue() + { + var queue = new Queue() + .Push(1) + .Push(2) + .Pop() + .Push(3) + .Push(4) + .Pop() + .Push(5) + ; + Assert.AreEqual("3 4 5 ", queue.Dump()); + } + + [TestMethod()] + public void Test_ForEach() + { + var sb = new StringBuilder(); + + var queue = new Queue() + .Push(1) + .Push(3) + .Push(5) + .ForEach(x => sb.AppendLine(x.ToString()), reappend: true) + ; + + Assert.AreEqual + ( + """ + 1 + 3 + 5 + + """, + sb.ToString().Print() + ); + } + + [TestMethod()] + public async Task Test_ForEachAsync() + { + var sb = new StringBuilder(); + + var queue = await new Queue() + .Push(1) + .Push(3) + .Push(5) + .ForEachAsync(x => sb.AppendLine(x.ToString()), reappend: true) + ; + + Assert.AreEqual + ( + """ + 1 + 3 + 5 + + """, + sb.ToString().Print() + ); + } + + [TestMethod()] + public void Test_IsEmpty() + { + Assert.AreEqual(true, new Queue().IsEmpty()); + + Assert.AreEqual + ( + true, + new Queue() + .Push(3) + .Push(5) + .Pop() + .Pop() + .IsEmpty() + ); + } +} diff --git a/Common.BasicHelper.Test/Utils/Extensions/StringHelper_Tests.cs b/Common.BasicHelper.Test/Utils/Extensions/StringHelper_Tests.cs new file mode 100644 index 0000000..149fc63 --- /dev/null +++ b/Common.BasicHelper.Test/Utils/Extensions/StringHelper_Tests.cs @@ -0,0 +1,81 @@ +using Common.BasicHelper.IO; + +namespace Common.BasicHelper.Utils.Extensions; + +[TestClass] +public class StringHelper_Tests +{ + [TestMethod] + public void Test_SeparateGroup() + { + var mac = "60F677F6C179"; + var formatedMac = mac.SeparateGroup(2, sb => sb.Append(':')); + Assert.AreEqual(formatedMac, "60:F6:77:F6:C1:79"); + } + + [TestMethod] + public void Test_IsNullOrEmpty() + { + string a = "asd"; + string b = " "; + string c = ""; + string? d = null; + + Assert.IsFalse(a.IsNullOrEmpty()); + Assert.IsFalse(b.IsNullOrEmpty()); + Assert.IsTrue(c.IsNullOrEmpty()); + Assert.IsTrue(d.IsNullOrEmpty()); + } + + [TestMethod] + public void Test_IsNullOrWhiteSpace() + { + string a = "asd"; + string b = " "; + string c = ""; + string? d = null; + + Assert.IsFalse(a.IsNullOrWhiteSpace()); + Assert.IsTrue(b.IsNullOrWhiteSpace()); + Assert.IsTrue(c.IsNullOrWhiteSpace()); + Assert.IsTrue(d.IsNullOrWhiteSpace()); + } + + [TestMethod()] + public void Test_Num2UpperChar() + { + Assert.AreEqual("23FJ325FSDF938".Num2UpperChar().Print(), "CDFJDCFFSDFJDI"); + } + + [TestMethod()] + public void Test_ReadAllTextFromDisk() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteIn(file, "Test"); + + var read = file.ReadAllTextFromDisk(); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } + + [TestMethod()] + public async Task Test_ReadAllTextFromDiskAsync() + { + var file = Path.GetTempFileName(); + + file.Print(); + + FileHelper.WriteIn(file, "Test"); + + var read = await file.ReadAllTextFromDiskAsync(); + + File.Delete(file); + + Assert.AreEqual(read, "Test"); + } +} diff --git a/Common.BasicHelper.Test/Utils/Extensions/Test_QueueHelper.cs b/Common.BasicHelper.Test/Utils/Extensions/Test_QueueHelper.cs deleted file mode 100644 index 2cbd5cd..0000000 --- a/Common.BasicHelper.Test/Utils/Extensions/Test_QueueHelper.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Common.BasicHelper.Utils.Extensions; - -namespace Common.BasicHelper.Test.Utils.Extensions; - -[TestClass] -public class Test_QueueHelper -{ - [TestMethod] - public void Test_QueueExtensions() - { - var queue = new Queue() - .Push(1) - .Push(2) - .Push(3) - .Push(4) - .Push(5) - .Push(6) - .Pop() - ; - while (queue.IsNotEmpty()) - { - queue = queue.ForEach(x => ++x); - queue = queue.Pop(); - } - Assert.AreEqual(0, queue.Count); - } - - [TestMethod] - public void Test_DumpQueue() - { - var queue = new Queue() - .Push(1) - .Push(2) - .Pop() - .Push(3) - .Push(4) - .Pop() - .Push(5) - ; - Assert.AreEqual("3 4 5 ", queue.Dump()); - } -} diff --git a/Common.BasicHelper.Test/Utils/Password_Tests.cs b/Common.BasicHelper.Test/Utils/Password_Tests.cs new file mode 100644 index 0000000..6127619 --- /dev/null +++ b/Common.BasicHelper.Test/Utils/Password_Tests.cs @@ -0,0 +1,12 @@ +namespace Common.BasicHelper.Utils; + +[TestClass] +public class Password_Tests +{ + [TestMethod] + public void Test_GeneratePassword() + { + foreach (var item in Enumerable.Range(0, 10)) + Console.WriteLine(Password.GeneratePassword(length: 12)); + } +} diff --git a/Common.BasicHelper.Test/Utils/Test_GUID.cs b/Common.BasicHelper.Test/Utils/Test_GUID.cs deleted file mode 100644 index d984328..0000000 --- a/Common.BasicHelper.Test/Utils/Test_GUID.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Common.BasicHelper.Utils; - -namespace Common.BasicHelper.Test.Utils; - -[TestClass] -public class Test_GUID -{ - [TestMethod] - public void Test_GenerateRandomGUIDPart() - { - for (int i = 0; i < 10; i++) - Console.WriteLine(GUID_Helper.Random_GUID_Generate().GetString()); - } -} \ No newline at end of file diff --git a/Common.BasicHelper.sln b/Common.BasicHelper.sln index fe3182e..4d30864 100644 --- a/Common.BasicHelper.sln +++ b/Common.BasicHelper.sln @@ -5,7 +5,9 @@ VisualStudioVersion = 17.1.32407.343 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.BasicHelper", "Common.BasicHelper\Common.BasicHelper.csproj", "{A80ED612-3DE2-4106-92C4-96940C93FD1C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.BasicHelper.Test", "Common.BasicHelper.Test\Common.BasicHelper.Test.csproj", "{D3DFF9AC-8CF1-42FF-BAF1-954A430DFDCE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Common.BasicHelper.Test", "Common.BasicHelper.Test\Common.BasicHelper.Test.csproj", "{D3DFF9AC-8CF1-42FF-BAF1-954A430DFDCE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common.BasicHelper.Samples", "Common.BasicHelper.Samples\Common.BasicHelper.Samples.csproj", "{C363C055-5CDC-4CEB-935C-D099CE0681BF}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -21,6 +23,10 @@ Global {D3DFF9AC-8CF1-42FF-BAF1-954A430DFDCE}.Debug|Any CPU.Build.0 = Debug|Any CPU {D3DFF9AC-8CF1-42FF-BAF1-954A430DFDCE}.Release|Any CPU.ActiveCfg = Release|Any CPU {D3DFF9AC-8CF1-42FF-BAF1-954A430DFDCE}.Release|Any CPU.Build.0 = Release|Any CPU + {C363C055-5CDC-4CEB-935C-D099CE0681BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C363C055-5CDC-4CEB-935C-D099CE0681BF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C363C055-5CDC-4CEB-935C-D099CE0681BF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C363C055-5CDC-4CEB-935C-D099CE0681BF}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Common.BasicHelper/Common.BasicHelper.csproj b/Common.BasicHelper/Common.BasicHelper.csproj index a367dfa..7375484 100644 --- a/Common.BasicHelper/Common.BasicHelper.csproj +++ b/Common.BasicHelper/Common.BasicHelper.csproj @@ -2,9 +2,9 @@ preview - netstandard2.1;net46 + netstandard2.1 disable - disable + enable True true Dynesshely diff --git a/Common.BasicHelper/Core/Shell/CommandsExecutor.cs b/Common.BasicHelper/Core/Shell/CommandsExecutor.cs index 91e789f..c31d266 100644 --- a/Common.BasicHelper/Core/Shell/CommandsExecutor.cs +++ b/Common.BasicHelper/Core/Shell/CommandsExecutor.cs @@ -1,6 +1,5 @@ using System; using System.Diagnostics; -using System.Text; using System.Threading; using System.Threading.Tasks; @@ -13,6 +12,7 @@ public static class CommandsExecutor /// /// 命令 /// 参数 + /// 是否在 Path 中寻找 /// 对启动信息的行动 /// 命令执行输出 public static string GetExecutionResult @@ -20,7 +20,7 @@ public static string GetExecutionResult string command, string args, bool findInPath = false, - Action action = null + Action? action = null ) { if (findInPath) @@ -34,9 +34,6 @@ public static string GetExecutionResult RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = false, - //StandardInputEncoding = Encoding.UTF8, - //StandardOutputEncoding = Encoding.UTF8, - //StandardErrorEncoding = Encoding.UTF8, CreateNoWindow = true, }; action?.Invoke(psi); @@ -60,6 +57,7 @@ public static string GetExecutionResult /// /// 命令 /// 参数 + /// 是否在 Path 中寻找 /// 针对启动信息的动作 /// 取消口令 /// 命令执行输出 @@ -68,8 +66,8 @@ public static async Task GetExecutionResultAsync string command, string args, bool findInPath = false, - Action action = null, - CancellationToken token = default + Action? action = null, + CancellationToken? token = default ) { if (findInPath) @@ -83,9 +81,6 @@ public static async Task GetExecutionResultAsync RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = false, - //StandardInputEncoding = Encoding.UTF8, - //StandardOutputEncoding = Encoding.UTF8, - //StandardErrorEncoding = Encoding.UTF8, CreateNoWindow = true, }; action?.Invoke(psi); @@ -95,22 +90,21 @@ public static async Task GetExecutionResultAsync StartInfo = psi, }; - var sb = new StringBuilder(); + //var sb = new StringBuilder(); - void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) - => sb.AppendLine(outLine.Data); + //void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine) + // => sb.AppendLine(outLine.Data); - process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); - process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); + //process.OutputDataReceived += new DataReceivedEventHandler(OutputHandler); + //process.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler); - await Task.Run(() => - { - process.Start(); + process.Start(); + + var output = process.StandardOutput.ReadToEnd(); - process.WaitForExit(); - }); + await Task.Run(process.WaitForExit); - return sb.ToString(); + return output; } } @@ -128,9 +122,9 @@ public static class CommandsExecutorExtensions public static string ExecuteAsCommand ( this string command, - string args = null, + string? args = null, bool findInPath = true, - Action action = null + Action? action = null ) => CommandsExecutor.GetExecutionResult ( @@ -140,4 +134,30 @@ public static string ExecuteAsCommand action ); + + /// + /// 将当前字符串作为命令执行, 异步获取命令执行输出 + /// + /// 命令 + /// 参数 + /// 是否在 Path 中寻找 + /// 针对启动信息的动作 + /// 取消口令 + /// 命令执行输出 + public static Task ExecuteAsCommandAsync + ( + this string command, + string? args = null, + bool findInPath = true, + Action? action = null, + CancellationToken? token = default + ) + => CommandsExecutor.GetExecutionResultAsync + ( + command, + args ?? "", + findInPath, + action, + token + ); } diff --git a/Common.BasicHelper/Graphics/Screen/Resolution.cs b/Common.BasicHelper/Graphics/Screen/Resolution.cs index 1fbd63b..3d0bbde 100644 --- a/Common.BasicHelper/Graphics/Screen/Resolution.cs +++ b/Common.BasicHelper/Graphics/Screen/Resolution.cs @@ -5,6 +5,39 @@ namespace Common.BasicHelper.Graphics.Screen; public class Resolution { + public static readonly List resolutions = new() + { + Parse("800x600", "SVGA"), + Parse("1024x768", "XGA"), + Parse("1280x720", "HD"), + Parse("1280x768", "WXGA"), + Parse("1280x800", "WXGA"), + Parse("1280x1024", "SXGA"), + Parse("1366x768", "WXSGA+"), + Parse("1440x900", "WXGA+"), + Parse("1600x1024", "WSXGA"), + Parse("1680x1050", "WSXGA+"), + Parse("1920x1080", "Full HD"), + Parse("1920x1200", "WUXGA"), + Parse("2048x1080", "2K Resolution"), + Parse("2048x1536", "QXGA"), + Parse("2560x1080", "QHD"), + Parse("2560x1440", "WQHD"), + Parse("2560x1600", "WQXGA"), + Parse("2560x2048", "QSXGA"), + Parse("3200x2048", "WQSXGA"), + Parse("3200x2400", "QUXGA"), + Parse("3440x1440", "Ulrea-Wide QHD"), + Parse("3840x2160", "4K UHD"), + Parse("3840x2400", "WQUXGA"), + Parse("4096x2160", "DCI 4K"), + Parse("5120x4096", "HSXGA"), + Parse("6400x4096", "WHSXGA"), + Parse("6400x4800", "HUXGA"), + Parse("7680x4320", "8K Ultra HD"), + Parse("7680x4800", "WHUXGA"), + }; + public double? Width { get; set; } public double? Height { get; set; } @@ -29,63 +62,6 @@ public Resolution Integerization() return this; } - /// - /// 重载运算符: 除法 - /// - /// 分辨率1 - /// 分辨率2 - /// 面积之比 - public static double? operator /(Resolution a, Resolution b) => a.Area / b.Area; - - /// - /// 重载运算符: 加法 - /// - /// 分辨率1 - /// 分辨率2 - /// 分辨率 - public static Resolution operator +(Resolution a, Resolution b) => new() - { - Width = a.Width + b.Width, - Height = a.Height + b.Height, - FramePerSecond = a.FramePerSecond + b.FramePerSecond, - Description = $"{a.Description}\nPlus\n{b.Description}" - }; - - /// - /// 重写 ToString() 方法 - /// - /// 表示分辨率及刷新率的字符串 - public override string ToString() - { - return $"{Width}x{Height}@{FramePerSecond}"; - } - - /// - /// 重写 Equals() 方法 - /// - /// 目标比较分辨率 - /// 是否相等 - public override bool Equals(object obj) - { - var res = obj as Resolution; - if (Width.Equals(res.Width) && Height.Equals(res.Height)) - if (FramePerSecond != null && res.FramePerSecond != null) - if (FramePerSecond.Equals(res.FramePerSecond)) - return true; - else return false; - else return true; - else return false; - } - - /// - /// 重写 GetHashCode() 方法 - /// - /// 哈希值 - public override int GetHashCode() => (int)(0 - + (Area.GetHashCode() ^ AspectRatio.GetHashCode()) - + (Width.GetHashCode() ^ Height.GetHashCode()) - + FramePerSecond == null ? 0 : FramePerSecond); - /// /// 根据字符串返回分辨率对象 /// @@ -95,13 +71,16 @@ public static Resolution Parse(string input) { var res_fps = input.Split('@'); var res = res_fps[0].Split('x'); + var resolution = new Resolution { Width = Convert.ToDouble(res[0]), Height = Convert.ToDouble(res[1]) }; + if (res_fps.Length == 2) resolution.FramePerSecond = Convert.ToDouble(res_fps[1]); else resolution.FramePerSecond = null; + return resolution; } @@ -113,52 +92,13 @@ public static Resolution Parse(string input) /// 分辨率对象 public static Resolution Parse(string input, string descr) { - var res_fps = input.Split('@'); - var res = res_fps[0].Split('x'); - var resolution = new Resolution() - { - Width = Convert.ToDouble(res[0]), - Height = Convert.ToDouble(res[1]), - Description = descr - }; - if (res_fps.Length == 2) resolution.FramePerSecond = Convert.ToDouble(res_fps[1]); - else resolution.FramePerSecond = null; + var resolution = Parse(input); + + resolution.Description = descr; + return resolution; } - public static readonly List resolutions = new() - { - Parse("800x600", "SVGA"), - Parse("1024x768", "XGA"), - Parse("1280x720", "HD"), - Parse("1280x768", "WXGA"), - Parse("1280x800", "WXGA"), - Parse("1280x1024", "SXGA"), - Parse("1366x768", "WXSGA+"), - Parse("1440x900", "WXGA+"), - Parse("1600x1024", "WSXGA"), - Parse("1680x1050", "WSXGA+"), - Parse("1920x1080", "Full HD"), - Parse("1920x1200", "WUXGA"), - Parse("2048x1080", "2K Resolution"), - Parse("2048x1536", "QXGA"), - Parse("2560x1080", "QHD"), - Parse("2560x1440", "WQHD"), - Parse("2560x1600", "WQXGA"), - Parse("2560x2048", "QSXGA"), - Parse("3200x2048", "WQSXGA"), - Parse("3200x2400", "QUXGA"), - Parse("3440x1440", "Ulrea-Wide QHD"), - Parse("3840x2160", "4K UHD"), - Parse("3840x2400", "WQUXGA"), - Parse("4096x2160", "DCI 4K"), - Parse("5120x4096", "HSXGA"), - Parse("6400x4096", "WHSXGA"), - Parse("6400x4800", "HUXGA"), - Parse("7680x4320", "8K Ultra HD"), - Parse("7680x4800", "WHUXGA"), - }; - /// /// 建议分辨率 /// @@ -189,6 +129,7 @@ public static Resolution Suggest(Resolution screen, Resolution content, Resoluti var suggest = new Resolution(); var yy = tararea / content.AspectRatio; + if (yy != null) { suggest.Height = System.Math.Sqrt((double)yy); @@ -201,4 +142,67 @@ public static Resolution Suggest(Resolution screen, Resolution content, Resoluti return suggest; } + + /// + /// 重载运算符: 除法 + /// + /// 分辨率1 + /// 分辨率2 + /// 面积之比 + public static double? operator /(Resolution a, Resolution b) => a.Area / b.Area; + + /// + /// 重载运算符: 加法 + /// + /// 分辨率1 + /// 分辨率2 + /// 分辨率 + public static Resolution operator +(Resolution a, Resolution b) => new() + { + Width = a.Width + b.Width, + Height = a.Height + b.Height, + FramePerSecond = a.FramePerSecond + b.FramePerSecond, + Description = $"{a.Description}\nPlus\n{b.Description}" + }; + + /// + /// 重写 ToString() 方法 + /// + /// 表示分辨率及刷新率的字符串 + public override string ToString() => + $"{Width}x{Height}{(FramePerSecond is null ? "" : "@")}{FramePerSecond}"; + + /// + /// 重写 Equals() 方法 + /// + /// 目标比较分辨率 + /// 是否相等 + public override bool Equals(object obj) + { + if (obj is not Resolution) + throw new ArgumentException($"CB0017: Only use `Equals` function for same type."); + + return GetHashCode() == obj.GetHashCode(); + + //if (obj is not Resolution res) return false; + + //if (Width.Equals(res.Width) && Height.Equals(res.Height)) + // if (FramePerSecond != null && res.FramePerSecond != null) + // if (FramePerSecond.Equals(res.FramePerSecond)) + // return true; + // else return false; + // else return true; + //else return false; + } + + /// + /// 重写 GetHashCode() 方法 + /// + /// 哈希值 + public override int GetHashCode() => (int)( + 0 + + (Area.GetHashCode() ^ AspectRatio.GetHashCode()) + + (Width.GetHashCode() ^ Height.GetHashCode()) + + FramePerSecond ?? 0 + ); } diff --git a/Common.BasicHelper/IO/DirectoryHelper.cs b/Common.BasicHelper/IO/DirectoryHelper.cs deleted file mode 100644 index 0b7400f..0000000 --- a/Common.BasicHelper/IO/DirectoryHelper.cs +++ /dev/null @@ -1,30 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace Common.BasicHelper.IO; - -public class DirectoryHelper -{ - /// - /// 获取一个文件夹包括子文件夹及其子文件的总大小 - /// - /// 文件夹路径 - /// 总大小 - public static long GetDirectorySize(string path) - { - var dir = Path.GetFullPath(path); - if (!Directory.Exists(dir)) return 0; - var dirs2For = new Queue(); - dirs2For.Enqueue(new DirectoryInfo(dir)); - long totalSize = 0; - while (dirs2For.Count > 0) - { - var folder = dirs2For.Dequeue(); - totalSize += folder.GetFiles().Sum(file => file.Length); - foreach (var subDir in folder.GetDirectories()) dirs2For.Enqueue(subDir); - } - - return totalSize; - } -} \ No newline at end of file diff --git a/Common.BasicHelper/IO/FileHelper.cs b/Common.BasicHelper/IO/FileHelper.cs index a12e5df..80b89c4 100644 --- a/Common.BasicHelper/IO/FileHelper.cs +++ b/Common.BasicHelper/IO/FileHelper.cs @@ -1,11 +1,8 @@ -using Common.BasicHelper.Utils; -using Common.BasicHelper.Utils.Extensions; +using Common.BasicHelper.Utils.Extensions; using System; using System.IO; using System.Threading.Tasks; -#pragma warning disable IDE0051 // 删除未使用的私有成员 - namespace Common.BasicHelper.IO; public class FileHelper @@ -15,30 +12,20 @@ public class FileHelper /// /// 指定的路径 /// 内容 - /// 写入是否成功以及异常信息 - public static Result WriteIn(string path, string content) + public static void WriteIn(string path, string content) { - try - { - if (File.Exists(path)) File.Delete(path); + if (File.Exists(path)) File.Delete(path); - File.Create(path).Close(); + File.Create(path).Close(); - var fs = new FileStream(path, FileMode.Open); - var sw = new StreamWriter(fs); + var fs = new FileStream(path, FileMode.Open); + var sw = new StreamWriter(fs); - sw.Write(content); - sw.Flush(); + sw.Write(content); + sw.Flush(); - sw.CloseAndDispose(); - fs.CloseAndDispose(); - - return new Result(true); - } - catch (Exception o) - { - throw new Result(o.Message); - } + sw.CloseAndDispose(); + fs.CloseAndDispose(); } /// @@ -47,36 +34,26 @@ public static Result WriteIn(string path, string content) /// 路径 /// 要追加的内容 public static void Append(string path, string content) - => WriteIn(path, $"{ReadAll(path)}\n{content}"); + => WriteIn(path, $"{ReadAll(path)}{Environment.NewLine}{content}"); /// /// 以二进制流写入指定路径全部内容 /// /// 路径 /// 内容 - /// 异常信息 - public static Result WriteByteIn(string path, byte[] content) + public static void WriteBytesTo(string path, byte[] content) { - try - { - if (!File.Exists(path)) - File.Create(path); + if (!File.Exists(path)) + File.Create(path); - var fs = new FileStream(path, FileMode.Open); - var bw = new BinaryWriter(fs); - - bw.Write(content); - bw.Flush(); + var fs = new FileStream(path, FileMode.Open); + var bw = new BinaryWriter(fs); - bw.CloseAndDispose(); - fs.CloseAndDispose(); + bw.Write(content); + bw.Flush(); - return new Result(true); - } - catch (Exception p) - { - throw new Result(p.Message); - } + bw.CloseAndDispose(); + fs.CloseAndDispose(); } /// @@ -98,7 +75,7 @@ public static void WriteBytesToFile(string path, byte[] content) /// /// 指定路径 /// 内容或异常信息 - public static string ReadAll(string path) + public static string? ReadAll(string path) { if (File.Exists(path)) { @@ -112,33 +89,25 @@ public static string ReadAll(string path) return content; } - else throw new Result("File didn't exists."); + else return null; } /// /// 异步读取指定路径的全部内容 /// /// 指定路径 - /// 内容或异常信息 - /// 异常 + /// 内容 public static async Task ReadAllAsync(string path) { - try - { - var fs = new FileStream(path, FileMode.Open); - var sr = new StreamReader(fs); + var fs = new FileStream(path, FileMode.Open); + var sr = new StreamReader(fs); - var result = await sr.ReadToEndAsync(); + var result = await sr.ReadToEndAsync(); - sr.CloseAndDispose(); - fs.CloseAndDispose(); + sr.CloseAndDispose(); + fs.CloseAndDispose(); - return result; - } - catch (Exception e) - { - throw new Result(e.Message); - } + return result; } /// @@ -146,7 +115,7 @@ public static async Task ReadAllAsync(string path) /// /// 路径 /// 二进制流 - public static byte[] ReadByteAll(string path) + public static byte[] ReadAllBytes(string path) { var fs = new FileStream(path, FileMode.Open); var br = new BinaryReader(fs); @@ -159,32 +128,13 @@ public static byte[] ReadByteAll(string path) return byData; } - /// - /// 二进制流读取文件 - /// - /// 文件路径 - /// 二进制流 - private static byte[] FileToBytes(string filePath) - { - var fi = new FileInfo(filePath); - var buffer = new byte[fi.Length]; - - var fs = fi.OpenRead(); - - fs.Read(buffer, 0, Convert.ToInt32(fi.Length)); - - fs.CloseAndDispose(); - - return buffer; - } - /// /// 二进制流创建文件 - /// 如果文件存在,则覆盖原文件 + /// 如果文件存在, 则覆盖原文件 /// /// 二进制流 /// 文件路径 - private static void CreateFile(byte[] fileBuffer, string newFilePath) + public static void CreateFile(byte[] fileBuffer, string newFilePath) { if (File.Exists(newFilePath)) File.Delete(newFilePath); @@ -199,81 +149,33 @@ private static void CreateFile(byte[] fileBuffer, string newFilePath) } /// - /// 递归删除目录下所有文件夹/文件包括子文件夹 - /// - /// 目录路径 - /// 删除操作结果 - /// 删除失败异常 - public static Result DeleteFolder(string path) - { - try - { - var directoryInfo = new DirectoryInfo(Path.GetFullPath(path)); - - foreach (var file in directoryInfo.GetFiles()) - file.Delete(); - - foreach (var directory in directoryInfo.GetDirectories()) - DeleteFolder(directory.FullName); - - directoryInfo.Delete(); - - return new Result(true); - } - catch (Exception e) - { - throw new Result(e.Message); - } - } - - /// - /// 将文件转换成byte[]数组 + /// 将文件转换成 byte 数组 /// /// 文件路径文件名称 - /// byte[]数组 - public static byte[] FileToByte(string fileUrl) + public static byte[] FileToBytes(string fileUrl) { - try - { - var fs = new FileStream(fileUrl, FileMode.Open, FileAccess.Read); - var byteArray = new byte[fs.Length]; + var fs = new FileStream(fileUrl, FileMode.Open, FileAccess.Read); + var byteArray = new byte[fs.Length]; - fs.Read(byteArray, 0, byteArray.Length); + fs.Read(byteArray, 0, byteArray.Length); - fs.CloseAndDispose(); + fs.CloseAndDispose(); - return byteArray; - } - catch (Exception e) - { - throw new Result(e.Message); - } + return byteArray; } /// - /// 将byte[]数组保存成文件 + /// 将 byte 数组保存成文件 /// - /// byte[]数组 + /// byte 数组 /// 保存至硬盘的文件路径 - /// 保存是否成功 - public static Result ByteToFile(byte[] byteArray, string fileName) + public static void ByteToFile(byte[] byteArray, string fileName) { - try - { - var fs = new FileStream(fileName, - FileMode.OpenOrCreate, FileAccess.Write); - - fs.Write(byteArray, 0, byteArray.Length); + var fs = new FileStream(fileName, + FileMode.OpenOrCreate, FileAccess.Write); - fs.CloseAndDispose(); + fs.Write(byteArray, 0, byteArray.Length); - return new Result(true); - } - catch (Exception e) - { - throw new Result(e.Message); - } + fs.CloseAndDispose(); } -} - -#pragma warning restore IDE0051 // 删除未使用的私有成员 +} \ No newline at end of file diff --git a/Common.BasicHelper/IO/PipeHelper.cs b/Common.BasicHelper/IO/PipeHelper.cs deleted file mode 100644 index 873aa3e..0000000 --- a/Common.BasicHelper/IO/PipeHelper.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System; -using System.IO; -using System.Text; - -namespace Common.BasicHelper.IO.PipeHelper; - -public class StreamString : IDisposable -{ - private readonly Stream ioStream; - private readonly UnicodeEncoding streamEncoding; - - public StreamString(Stream ioStream) - { - this.ioStream = ioStream; - streamEncoding = new UnicodeEncoding(); - } - - /// - /// 读取字符串 - /// - /// 字符串 - public string ReadString() - { - var len = ioStream.ReadByte() * 256; - len += ioStream.ReadByte(); - - var inBuffer = new byte[len]; - ioStream.Read(inBuffer, 0, len); - - return streamEncoding.GetString(inBuffer); - } - - /// - /// 写入字符串 - /// - /// 字符串 - /// 写出缓冲区长度 - public int WriteString(string outString) - { - var outBuffer = streamEncoding.GetBytes(outString); - var len = outBuffer.Length; - - if (len > ushort.MaxValue) - len = ushort.MaxValue; - - ioStream.WriteByte((byte)(len / 256)); - ioStream.WriteByte((byte)(len & 255)); - ioStream.Write(outBuffer, 0, len); - - ioStream.Flush(); - - return outBuffer.Length + 2; - } - - public void Dispose() - { - ioStream.Close(); - ioStream.Dispose(); - GC.SuppressFinalize(this); - } -} diff --git a/Common.BasicHelper/Math/Standard.cs b/Common.BasicHelper/Math/Standard.cs index e997701..54e32b7 100644 --- a/Common.BasicHelper/Math/Standard.cs +++ b/Common.BasicHelper/Math/Standard.cs @@ -61,11 +61,16 @@ public static T Max(params T[] input) where T : IComparable /// 指示要被获取指定位数字的数字 /// 指示要获取的位数 /// 返回指定位上数字 - public static int GetBit(int number, int bit) + public static int GetPosition(int number, int bit) { var pow = 10; - for (var i = 0; i < bit - 1; ++i) + for (var i = 0; i < bit - 2; ++i) pow *= pow; return (number % pow) / (pow / 10); } } + +public static class StandardExtensions +{ + public static int GetPosition(this int number, int bit) => Standard.GetPosition(number, bit); +} diff --git a/Common.BasicHelper/Math/Tricks.cs b/Common.BasicHelper/Math/Tricks.cs index e438286..aff4df5 100644 --- a/Common.BasicHelper/Math/Tricks.cs +++ b/Common.BasicHelper/Math/Tricks.cs @@ -26,9 +26,9 @@ public static string GetMultiplicationTable(int from, int to, bool direction = t } else { - for (var x = from; x >= from; --x) + for (var x = from; x >= to; --x) { - for (var y = from; y <= x; ++y) + for (var y = from; y >= x; --y) sb.Append($"{y}*{x}={x * y}\t"); sb.AppendLine(); } diff --git a/Common.BasicHelper/NET/BasicNet.cs b/Common.BasicHelper/Network/NetUtils.cs similarity index 51% rename from Common.BasicHelper/NET/BasicNet.cs rename to Common.BasicHelper/Network/NetUtils.cs index 79dbb2f..06e4f53 100644 --- a/Common.BasicHelper/NET/BasicNet.cs +++ b/Common.BasicHelper/Network/NetUtils.cs @@ -1,72 +1,37 @@ using Common.BasicHelper.Utils.Extensions; -using System; using System.IO; using System.Net; using System.Net.NetworkInformation; using System.Text; -namespace Common.BasicHelper.Net; +namespace Common.BasicHelper.Network; -public class BasicNet +public class NetUtils { /// /// 检验是否拥有网络连接 /// /// 测试的目标 - /// 等待时间 + /// 等待毫秒数 /// 是否拥有网络连接 - public static bool IsWebConected(string target, int waitTime) + public static bool IsWebConected(string target, int timeOutMilliseconds) { - try + var pingSender = new Ping(); + var pingOptions = new PingOptions { - var objPingSender = new Ping(); - var objPinOptions = new PingOptions - { - DontFragment = true - }; - var data = ""; - var buffer = Encoding.UTF8.GetBytes(data); - var objPinReply = objPingSender.Send(target, - waitTime, buffer, objPinOptions); - var strInfo = objPinReply.Status.ToString(); - if (strInfo == "Success") - { - return true; - } - return false; - } - catch - { - return false; - } - } + DontFragment = true + }; - /// - /// 返回网络连接失败的原因 - /// - /// 测试目标 - /// 等待时间 - /// 返回失败原因 - public static Exception WebConectionError(string target, int waitTime) - { - try - { - var objPingSender = new Ping(); - var objPinOptions = new PingOptions - { - DontFragment = true - }; - var data = ""; - var buffer = Encoding.UTF8.GetBytes(data); - var objPinReply = objPingSender.Send(target, - waitTime, buffer, objPinOptions); - var strInfo = objPinReply.Status.ToString(); - return null; - } - catch (Exception result) - { - return result; - } + var data = ""; + var buffer = Encoding.UTF8.GetBytes(data); + + var pingReply = pingSender.Send(target, + timeOutMilliseconds, buffer, pingOptions); + var strInfo = pingReply.Status.ToString(); + + if (strInfo.Equals("Success")) + return true; + return false; } /// diff --git a/Common.BasicHelper/Time/NTP.cs b/Common.BasicHelper/Time/NTP.cs new file mode 100644 index 0000000..4d5c473 --- /dev/null +++ b/Common.BasicHelper/Time/NTP.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Common.BasicHelper.Time; + +public class NTP +{ + /// + /// 获取目标时间与本地时间的差值毫秒数 + /// + /// 报文发送时本地时间 + /// 报文送达时远程时间 + /// 报文返回时远程时间 + /// 报文抵达时本地时间 + /// 目标时间与本地时间差值毫秒数 + public static double GetOffset(DateTime t1, DateTime t2, DateTime t3, DateTime t4) + { + // NTP Protocal + // + // totalDelay = (t4 - t1) - (t3 - t2) + // delay = totalDelay / 2 + // + // { t2 = t1 + offset + delay + // { t4 = t3 - offset + delay + // + // => offset = ((t2 - t1) + (t3 - t4)) / 2 + + var offset = (t2 - t1 + (t3 - t4)).TotalMilliseconds; + + return offset; + } + + /// + /// 获取目标时间与本地时间的差值 + /// + /// 报文发送时本地时间 + /// 报文送达时远程时间 + /// 报文返回时远程时间 + /// 报文抵达时本地时间 + /// 目标时间与本地时间差值 + public static TimeSpan GetOffsetTimeSpan(DateTime t1, DateTime t2, DateTime t3, DateTime t4) + => TimeSpan.FromMilliseconds(GetOffset(t1, t2, t3, t4)); +} diff --git a/Common.BasicHelper/Utils/COID.cs b/Common.BasicHelper/Utils/COID.cs new file mode 100644 index 0000000..db060d0 --- /dev/null +++ b/Common.BasicHelper/Utils/COID.cs @@ -0,0 +1,187 @@ +using Common.BasicHelper.Math; +using System; +using System.Text.RegularExpressions; + +namespace Common.BasicHelper.Utils; + +public static class COID_Helper +{ + /// + /// 从字符串构造 COID 对象 + /// + /// COID 字符串 + /// 数据分隔符, 默认为'-' + /// 一个 COID 对象 + public static COID Build_COID(string coid_str, char sep = '-') => new(coid_str, sep); + + /// + /// 从字符串中构造 COID_Part 对象 + /// + /// 字符串 + /// 一个 COID_Part 对象 + public static COID_Part Build_COID_Part(string coid_part) => new(coid_part); + + /// + /// 检查格式 + /// + /// 部分 COID + /// 是否合法 + public static bool FormatCheck(COID_Part part) + { + var tmp = part.ToString(); + for (int i = 0; i < 5; i++) + if (!Regex.IsMatch(tmp[i].ToString(), RegexStrings.COID_Part_Parttern)) + return false; + return true; + } + + /// + /// 生成一个随机字符, 但符合 [RegexStrings].COID_Part_Parttern + /// + /// 一个随机字符 + public static char RandomCharGenerate() + { + var rst = (char)('0' - 1); + while (!Regex.IsMatch(rst.ToString(), RegexStrings.COID_Part_Parttern)) + rst = (char)new Random().Next(Standard.Min('a', 'A', '0'), + Standard.Max('z', 'Z', '9')); + return rst; + } + + /// + /// 生成一个随机 COID, COID_Part 来源 Random_COID_Part_Generate() 函数 + /// + /// 一个 COID + public static COID Random_COID_Generate() => new() + { + A = Random_COID_Part_Generate(), + B = Random_COID_Part_Generate(), + C = Random_COID_Part_Generate(), + D = Random_COID_Part_Generate(), + E = Random_COID_Part_Generate(), + }; + + /// + /// 生成一个随机部分COID, 字符来源 RandomCharGenerate() 函数 + /// + /// 一个部分COID + public static COID_Part Random_COID_Part_Generate() => new( + string.Concat( + RandomCharGenerate(), + RandomCharGenerate(), + RandomCharGenerate(), + RandomCharGenerate(), + RandomCharGenerate() + ) + ); +} + +public class COID +{ + private readonly COID_Part[] parts = new COID_Part[5]; + + public COID_Part A { get => parts[0]; set => parts[0] = value; } + + public COID_Part B { get => parts[1]; set => parts[1] = value; } + + public COID_Part C { get => parts[2]; set => parts[2] = value; } + + public COID_Part D { get => parts[3]; set => parts[3] = value; } + + public COID_Part E { get => parts[4]; set => parts[4] = value; } + + public COID() + { + + } + + /// + /// COID 的构造函数 + /// + /// 输入字符串 + /// 分隔符, 默认为 '-' + /// 参数长度错误异常 + public COID(string input, char sep = '-') + { + parts = new COID_Part[5]; + var tmp = input.Split(sep); + + if (tmp.Length != 5) + throw new ArgumentException("CB0033: Error input format, it should be 5 parts."); + + for (int i = 0; i < 5; i++) + parts[i] = new(tmp[i]); + } + + /// + /// 返回字符串 + /// + /// 分隔符, 默认为'-' + /// 字符串 + public string GetString(char sep = '-') => $"{A}{sep}{B}{sep}{C}{sep}{D}{sep}{E}"; + + /// + /// 重写 ToString() 方法, 返回形如 `P831N-MQV15-2D6UC-KKWXH-3IHI7` 的字符串 + /// + /// 字符串 + public override string ToString() => $"{A}-{B}-{C}-{D}-{E}"; + + /// + /// 重载判等方法 + /// + /// 判等对象 + /// 是否相等 + public override bool Equals(object obj) => ToString().Equals(obj.ToString()); + + /// + /// 重载哈希方法 + /// + /// 哈希值 + public override int GetHashCode() => ToString().GetHashCode(); +} + +public class COID_Part +{ + private readonly char[] ids = new char[5]; + + public char A { get => ids[0]; set => ids[0] = value; } + + public char B { get => ids[1]; set => ids[1] = value; } + + public char C { get => ids[2]; set => ids[2] = value; } + + public char D { get => ids[3]; set => ids[3] = value; } + + public char E { get => ids[4]; set => ids[4] = value; } + + public COID_Part() + { + + } + + /// + /// COID_Part 的构造函数 + /// + /// 输入字符串 + /// 参数长度错误 + /// COID_Part 格式错误 + public COID_Part(string input) + { + ids = new char[5]; + + if (input.Length != 5) + throw new ArgumentException("CB0034: Error input length, it should be 5."); + else + for (int i = 0; i < 5; i++) + ids[i] = input[i]; + + if (!COID_Helper.FormatCheck(this)) + throw new FormatException("CB0035: Error COID_Part format."); + } + + /// + /// 重写 ToString() 方法, 返回形如 `2D6UC` 的字符串 + /// + /// 字符串 + public override string ToString() => $"{A}{B}{C}{D}{E}".ToUpper(); +} diff --git a/Common.BasicHelper/Utils/Extensions/CleanHelper.cs b/Common.BasicHelper/Utils/Extensions/CleanHelper.cs index 1929174..6ced087 100644 --- a/Common.BasicHelper/Utils/Extensions/CleanHelper.cs +++ b/Common.BasicHelper/Utils/Extensions/CleanHelper.cs @@ -1,6 +1,10 @@ using System; +using System.Diagnostics; using System.IO; +using System.IO.Pipes; using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; namespace Common.BasicHelper.Utils.Extensions; @@ -11,19 +15,48 @@ public static class CleanHelper /// /// 对象类型 /// 对象 - public static void CloseAndDispose(this T obj) where T : IDisposable + /// 是否跳过关闭 + public static void CloseAndDispose(this T obj, bool skipClose = false) where T : IDisposable { - if (obj is Stream) (obj as Stream).Close(); - else if (obj is BinaryReader) (obj as BinaryReader).Close(); + if (skipClose) { } - else if (obj is BinaryWriter) (obj as BinaryWriter).Close(); + else if (obj is Stream stream) stream?.Close(); - else if (obj is TextReader) (obj as TextReader).Close(); + // Below types based on `Stream` + // + // - FileStream + // - MemoryStream + // - CryptoStream + // - NetworkStream + // - DeflateStream + // - GZipStream - else if (obj is TextWriter) (obj as TextWriter).Close(); + else if (obj is PipeStream pipeStream) pipeStream?.Close(); - else if (obj is WebResponse) (obj as WebResponse).Close(); + // Below types based on `PipeStream`: + // + // - NamedPipeClientStream + // - NamedPipeServerStream + + else if (obj is BinaryReader binaryReader) binaryReader?.Close(); + + else if (obj is BinaryWriter binaryWriter) binaryWriter?.Close(); + + else if (obj is TextReader textReader) textReader?.Close(); + + else if (obj is TextWriter textWriter) textWriter?.Close(); + + // Below types based on `TextReader` or `TextWriter` + // + // - StreamReader + // - StreamWriter + + else if (obj is WebResponse webResponse) webResponse?.Close(); + + else if (obj is Process process) process?.Close(); + + else if (obj is Socket socket) socket?.Close(); obj.Dispose(); } diff --git a/Common.BasicHelper/Utils/Extensions/Dumpper.cs b/Common.BasicHelper/Utils/Extensions/Dumpper.cs index db4f8ee..19ce0ec 100644 --- a/Common.BasicHelper/Utils/Extensions/Dumpper.cs +++ b/Common.BasicHelper/Utils/Extensions/Dumpper.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Net.NetworkInformation; using System.Text; @@ -13,14 +14,15 @@ public static class Dumpper /// 队列 /// 分隔符 /// 打印内容 - public static string Dump(this Queue queue, string separater = " ") + public static string Dump(this Queue queue, string separater = " ", bool print = true) { var result = new StringBuilder(); queue.ForEach(x => { - result.Append(x.ToString()); + result.Append(x?.ToString()); result.Append(separater); }, true); + if (print) result.ToString().Print(); return result.ToString(); } @@ -30,10 +32,11 @@ public static string Dump(this Queue queue, string separater = " ") /// 队列类型 /// 队列 /// 打印内容 - public static string[] Dump2Lines(this Queue queue) + public static string[] Dump2Lines(this Queue queue, bool print = true) { var result = new List(); - queue.ForEach(x => result.Add(x.ToString()), true); + queue.ForEach(x => result.Add(x?.ToString() ?? string.Empty), true); + if (print) result.ToArray().Print(); return result.ToArray(); } @@ -42,7 +45,7 @@ public static string[] Dump2Lines(this Queue queue) /// /// 网络适配器 /// 打印内容 - public static string Dump(this NetworkInterface adapter) + public static string Dump(this NetworkInterface adapter, bool print = true) { var sb = new StringBuilder(); var adapterProperties = adapter.GetIPProperties(); @@ -85,6 +88,8 @@ public static string Dump(this NetworkInterface adapter) sb.AppendLine(new StringBuilder().Append('-', 50).ToString()); } + if (print) sb.ToString().Print(); + return sb.ToString(); } @@ -93,7 +98,7 @@ public static string Dump(this NetworkInterface adapter) /// /// 网络适配器 /// 打印内容 - public static string[] Dump2Lines(this NetworkInterface adapter) + public static string[] Dump2Lines(this NetworkInterface adapter, bool print = true) { var sb = new List(); var adapterProperties = adapter.GetIPProperties(); @@ -135,6 +140,70 @@ public static string[] Dump2Lines(this NetworkInterface adapter) sb.Add($"{"IP地址: "}{v4s.IncomingUnknownProtocolPackets}"); sb.Add(new StringBuilder().Append('-', 50).ToString()); } + + if (print) sb.ToArray().Print(); + return sb.ToArray(); } + + /// + /// 任意类型打印机 + /// + /// 打印对象 + public static string Print(this T? src) + { + Console.WriteLine(src?.ToString()); + return src?.ToString() ?? ""; + } + + /// + /// 打印任意类型数组 + /// + /// 数组类型 + /// 数组对象 + /// 连接字符串 + /// 是否裁剪末尾连接字符串 + /// 对于 string 数组是否使用换行替代连接 + /// 打印出的字符串 + public static string Print + ( + this IEnumerable array, + string? connection = ", ", + bool cutEnding = true, + bool newLineConnection4StringArray = true, + bool print = true + ) + { + if (array is Queue queue) return Dump(queue, connection ?? " ", print); + + var sb = new StringBuilder(); + + var useNewLine2ReplaceConnectionString + = newLineConnection4StringArray && array is IEnumerable; + + foreach (var item in array) + { + sb.Append(item?.ToString()); + + if (useNewLine2ReplaceConnectionString) + sb.Append(Environment.NewLine); + else sb.Append(connection); + } + + var result = sb.ToString(); + + if (useNewLine2ReplaceConnectionString) + { + Console.WriteLine(result); + + return result; + } + + if (cutEnding) + result = result[..(sb.Length - connection?.Length ?? 0)]; + + Console.WriteLine(result); + + return result; + } } diff --git a/Common.BasicHelper/Utils/Extensions/ListHelper.cs b/Common.BasicHelper/Utils/Extensions/ListHelper.cs index bbd286a..9c635d6 100644 --- a/Common.BasicHelper/Utils/Extensions/ListHelper.cs +++ b/Common.BasicHelper/Utils/Extensions/ListHelper.cs @@ -12,17 +12,19 @@ public static class ListHelper /// 列表 /// 分隔符 /// 自定义字符串 - public static string ToCustomString(this List list, string separater = ",") + public static string ToCustomString(this List list, string separater = ",", bool cutEnding = true) { var sb = new StringBuilder(); foreach (var item in list) { - sb.Append(item.ToString()); + sb.Append(item?.ToString()); sb.Append(separater); } - return sb.ToString(); + var result = sb.ToString(); + + return cutEnding ? result[0..(result.Length - separater.Length)] : result; } } diff --git a/Common.BasicHelper/Utils/Extensions/QueueHelper.cs b/Common.BasicHelper/Utils/Extensions/QueueHelper.cs index 38c3f53..c14ad28 100644 --- a/Common.BasicHelper/Utils/Extensions/QueueHelper.cs +++ b/Common.BasicHelper/Utils/Extensions/QueueHelper.cs @@ -58,7 +58,7 @@ public static Queue Pop(this Queue queue) /// 操作锁 /// 队列本身 public static Queue ForEach(this Queue queue, Action action, - bool reappend = false, object locker = null) + bool reappend = false, object? locker = null) { Queue func() { @@ -73,7 +73,7 @@ Queue func() return queue; } - if (locker != null) + if (locker is not null) { lock (locker) { diff --git a/Common.BasicHelper/Utils/Extensions/StringHelper.cs b/Common.BasicHelper/Utils/Extensions/StringHelper.cs index 2963b35..eb18529 100644 --- a/Common.BasicHelper/Utils/Extensions/StringHelper.cs +++ b/Common.BasicHelper/Utils/Extensions/StringHelper.cs @@ -1,4 +1,5 @@ -using System.IO; +using System; +using System.IO; using System.Text; using System.Threading.Tasks; @@ -32,27 +33,76 @@ public static string Num2UpperChar(this string source) /// /// 文件路径 /// 文本内容, 若文件不存在则返回空 - public static string ReadAllTextFromDisk(this string path) + public static string? ReadAllTextFromDisk(this string path) { if (File.Exists(path)) return File.ReadAllText(path); else return null; } -#if NETSTANDARD2_1_OR_GREATER - /// /// 从磁盘异步读取全部文本 /// /// 文件路径 /// 文本内容读取任务, 若文件不存在则返回空 - public static Task ReadAllTextFromDiskAsync(this string path) + public static async Task ReadAllTextFromDiskAsync(this string path) { if (File.Exists(path)) - return File.ReadAllTextAsync(path); + return await File.ReadAllTextAsync(path); else return null; } -#endif + /// + /// 对字符串进行按指定数量分组拼接 + /// + /// 字符串 + /// 每组字符数 + /// 每组分割完后动作 + /// 最后一组分割完成后是否执行动作 + /// 返回拼接结果 + public static string SeparateGroup + ( + this string text, + int count, + Action? action = null, + bool executeAfterLastGroup = false + ) + { + var sb = new StringBuilder(); + for (int i = 0, j = 0; i < text.Length; ++i) + { + void normalSeparate() + { + sb.Append(text[i]); + ++j; + } + + normalSeparate(); + if (j == count) + { + if (i != text.Length - 1) + action?.Invoke(sb); + else if (executeAfterLastGroup) + action?.Invoke(sb); + + j = 0; + } + } + return sb.ToString(); + } + + /// + /// 判断字符串是否为空 + /// + /// 字符串对象 + /// 是否为空 + public static bool IsNullOrEmpty(this string? str) => string.IsNullOrEmpty(str); + + /// + /// 判断字符串是否为空或仅由空白组成 + /// + /// 字符串对象 + /// 是否为空或仅有空白组成 + public static bool IsNullOrWhiteSpace(this string? str) => string.IsNullOrWhiteSpace(str); } diff --git a/Common.BasicHelper/Utils/GUID.cs b/Common.BasicHelper/Utils/GUID.cs deleted file mode 100644 index abfe020..0000000 --- a/Common.BasicHelper/Utils/GUID.cs +++ /dev/null @@ -1,159 +0,0 @@ -using Common.BasicHelper.Math; -using System; -using System.Text; -using System.Text.RegularExpressions; - -namespace Common.BasicHelper.Utils; - -public static class GUID_Helper -{ - /// - /// 检查格式 - /// - /// 部分GUID - /// 是否合法 - public static bool FormatCheck(GUID_Part part) - { - string tmp = part.GetString(); - for (int i = 0; i < 5; i++) - if (!Regex.IsMatch(tmp[i].ToString(), RegexStrings.GUID_Part_Parttern)) - return false; - return true; - } - - /// - /// 生成一个随机字符, 但符合 [RegexStrings].GUID_Part_Parttern - /// - /// 一个随机字符 - public static char RandomCharGenerate() - { - char rst = (char)('0' - 1); - while (!Regex.IsMatch(rst.ToString(), RegexStrings.GUID_Part_Parttern)) - rst = (char)new Random().Next(Standard.Min('a', 'A', '0'), - Standard.Max('z', 'Z', '9')); - return rst; - } - - /// - /// 生成一个随机部分GUID, 字符来源 RandomCharGenerate() 函数 - /// - /// 一个部分GUID - public static GUID_Part Random_GUID_Part_Generate() => new( - string.Concat(RandomCharGenerate(), - RandomCharGenerate(), RandomCharGenerate(), RandomCharGenerate(), RandomCharGenerate())); - - /// - /// 生成一个随机GUID, 部分GUID来源 Random_GUID_Part_Generate() 函数 - /// - /// 一个GUID - public static GUID Random_GUID_Generate() => new( - $"{Random_GUID_Part_Generate().GetString()}-" + - $"{Random_GUID_Part_Generate().GetString()}-" + - $"{Random_GUID_Part_Generate().GetString()}-" + - $"{Random_GUID_Part_Generate().GetString()}-" + - $"{Random_GUID_Part_Generate().GetString()}" - ); -} - -public readonly struct GUID -{ - private readonly GUID_Part[] parts; - - public GUID_Part A { get => parts[0]; set => parts[0] = value; } - - public GUID_Part B { get => parts[1]; set => parts[1] = value; } - - public GUID_Part C { get => parts[2]; set => parts[2] = value; } - - public GUID_Part D { get => parts[3]; set => parts[3] = value; } - - public GUID_Part E { get => parts[4]; set => parts[4] = value; } - - /// - /// GUID的构造函数 - /// - /// 输入字符串 - /// 分隔符, 默认为'-' - /// 格式错误异常 - public GUID(string input, char sep = '-') - { - parts = new GUID_Part[5]; - string[] tmp = input.Split(sep); - if (tmp.Length != 5) throw new Result("Error input format!"); - for (int i = 0; i < 5; i++) - parts[i] = GUID_Part.BuildFromString(tmp[i]); - } - - /// - /// 从字符串构造GUID - /// - /// 输入数据 - /// 数据分隔符, 默认为'-' - /// 一个GUID - public static GUID BuildFromString(string input, char sep = '-') => new(input, sep); - - /// - /// 返回字符串 - /// - /// 分隔符, 默认为'-' - /// 字符串 - public string GetString(char sep = '-') - { - var sb = new StringBuilder(); - for (int i = 0; i < 5; i++) - sb.Append($"{parts[i].GetString()}{(i == 4 ? "" : sep.ToString())}"); - return sb.ToString(); - } -} - -public readonly struct GUID_Part -{ - private readonly char[] ids; - - public char A { get => ids[0]; set => ids[0] = value; } - - public char B { get => ids[1]; set => ids[1] = value; } - - public char C { get => ids[2]; set => ids[2] = value; } - - public char D { get => ids[3]; set => ids[3] = value; } - - public char E { get => ids[4]; set => ids[4] = value; } - - /// - /// 部分GUID的构造函数 - /// - /// 输入字符串 - /// 构造失败, 格式错误 - public GUID_Part(string input) - { - ids = new char[5]; - - if (input.Length != 5) - throw new Result("Error argument length."); - else - for (int i = 0; i < 5; i++) - ids[i] = input[i]; - if (!GUID_Helper.FormatCheck(this)) - throw new Result("Error guid_part format."); - } - - /// - /// 从字符串中构造 - /// - /// 字符串 - /// 部分GUID - public static GUID_Part BuildFromString(string input) => new(input); - - /// - /// 返回字符串 - /// - /// 字符串 - public string GetString() - { - var sb = new StringBuilder(); - for (int i = 0; i < 5; i++) - sb.Append(ids[i]); - return sb.ToString().ToUpper(); - } -} diff --git a/Common.BasicHelper/Utils/Password.cs b/Common.BasicHelper/Utils/Password.cs new file mode 100644 index 0000000..f5984aa --- /dev/null +++ b/Common.BasicHelper/Utils/Password.cs @@ -0,0 +1,99 @@ +using System; +using System.Linq; +using System.Text; + +namespace Common.BasicHelper.Utils; + +public class Password +{ + public const string AllUppercases = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + public const string AllLowercases = "abcdefghijklmnopqrstuvwxyz"; + + public const string AllNumbers = "0123456789"; + + public const string AllSymbols = @"!@#$%^&*()_+-=[]{};':,./<>?"; + + /// + /// 生成密码 + /// + /// 确切长度 + /// 长度范围始 + /// 长度范围终 + /// 是否包含大写字母 + /// 是否包含小写字母 + /// 是否包含数字 + /// 是否包含符号 + /// 支持的大写字母集 + /// 支持的小写字母集 + /// 支持的数字集 + /// 支持的符号集 + /// 生成的密码 + public static string GeneratePassword + ( + int? length = null, + int? lengthRangeStart = null, + int? lengthRangeEnd = null, + bool includeUppercase = true, + bool includeLowercase = true, + bool includeNumbers = true, + bool includeSymbols = true, + string supportedUppercases = AllUppercases, + string supportedLowercases = AllLowercases, + string supportedNumbers = AllNumbers, + string supportedSymbols = AllSymbols + ) + { + #region Guard Blocks + + var actualLengthProvided = length is not null; + + var rangeLengthProvided = lengthRangeStart is not null && lengthRangeEnd is not null; + + var lengthProvided = actualLengthProvided || rangeLengthProvided; + + var noCharIncluded = true + && !includeUppercase + && !includeLowercase + && !includeNumbers + && !includeSymbols; + + var noSupportedChars = true + && supportedUppercases.Length == 0 + && supportedLowercases.Length == 0 + && supportedNumbers.Length == 0 + && supportedSymbols.Length == 0; + + if (!lengthProvided) throw new ArgumentException("CB0027: No length provided."); + + if (noCharIncluded) throw new ArgumentException("CB0028: At least one char type included."); + + if (noSupportedChars) throw new ArgumentException("CB0029: No supported chars provided."); + + #endregion Guard Blocks + + var sb = new StringBuilder(); + + var random = new Random(); + + var chars = new string[4] + { + supportedUppercases, + supportedLowercases, + supportedNumbers, + supportedSymbols + }; + + var generateLength = length + ?? random.Next(lengthRangeStart ?? 0, lengthRangeEnd ?? 13); + + var selected = from item in Enumerable.Range(0, generateLength) + let selection = chars[random.Next(0, chars.Length)] + select selection[random.Next(0, selection.Length)]; + + foreach (var item in selected) + sb.Append(item); + + return sb.ToString(); + } +} diff --git a/Common.BasicHelper/Utils/Platform.cs b/Common.BasicHelper/Utils/Platform.cs deleted file mode 100644 index f212874..0000000 --- a/Common.BasicHelper/Utils/Platform.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Common.BasicHelper.Utils; - -public struct Platform -{ - - /// - /// 平台名称 - /// - public string Name { get; set; } - - /// - /// 平台版本 - /// - public string Version { get; set; } - - /// - /// 最小支持版本 - /// - public Version MinistVersion { get; set; } -} diff --git a/Common.BasicHelper/Utils/RegexStrings.cs b/Common.BasicHelper/Utils/RegexStrings.cs index 94cb468..0a692a8 100644 --- a/Common.BasicHelper/Utils/RegexStrings.cs +++ b/Common.BasicHelper/Utils/RegexStrings.cs @@ -2,7 +2,7 @@ public struct RegexStrings { - public const string GUID_Part_Parttern = @"([A-Z]|[a-z]|[0-9])"; + public const string COID_Part_Parttern = @"([A-Z]|[a-z]|[0-9])"; public const string Version_Parse_STR = @"([0-9]*\.[0-9]*\.[0-9]*(\.[0-9]*)?)"; } diff --git a/Common.BasicHelper/Utils/Result.cs b/Common.BasicHelper/Utils/Result.cs deleted file mode 100644 index 522a96e..0000000 --- a/Common.BasicHelper/Utils/Result.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; - -namespace Common.BasicHelper.Utils; - -public class Result : Exception -{ - - private bool hasProblem = false; - - /// - /// 是否存在问题 - /// - public bool HasProblem - { - get { return hasProblem; } - set { hasProblem = value; } - } - - private object returnResult = string.Empty; - - /// - /// 返回结果 - /// - public object ReturnResult - { - get { return returnResult; } - set - { - returnResult = value; - returnType = value.GetType(); - } - } - - private Type returnType = typeof(string); - - /// - /// 返回值类型 - /// - public Type ReturnType - { - get { return returnType; } - } - - /// - /// 异常状态下的构造函数 - /// - /// 异常消息 - /// 是否存在问题, 默认存在 - public Result(string message, bool hasProblem = true) : base(message) => HasProblem = hasProblem; - - /// - /// 正常状态下的构造函数 - /// - /// 返回结果 - public Result(T result) - { - if (result != null) - { - ReturnResult = result; - } - } -} diff --git a/Common.BasicHelper/Utils/Version.cs b/Common.BasicHelper/Utils/Version.cs deleted file mode 100644 index 5479217..0000000 --- a/Common.BasicHelper/Utils/Version.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; - -namespace Common.BasicHelper.Utils; - -public struct Version -{ - - private ushort majorVersion; - private ushort minorVersion; - private ushort branchVersion; - private ushort buildVersion; - - public List SupportedArchitectures => new(); - - public List SupportedPlatforms => new(); - - /// - /// 设置版本 - /// - /// 主版本号 - /// 副版本号 - /// 分支版本号 - /// 构建版本号 - public void SetVersion(ushort major, ushort minor, ushort branch, ushort build) - { - majorVersion = major; - minorVersion = minor; - branchVersion = branch; - buildVersion = build; - } - - /// - /// 增加一个受支持的架构 - /// - /// 架构 - public void AddSupportedArchitecture(Architecture arch) => SupportedArchitectures.Add(arch); - - /// - /// 增加一个受支持的平台 - /// - /// 平台 - public void AddPlatform(Platform platform) => SupportedPlatforms.Add(platform); - - /// - /// 版本类别 - /// - public enum Type - { - Debug = 0, Preview = 1, - Release = 2, Latest = 3 - } - - /// - /// 版本状态 - /// - public enum State - { - Developing = 0, Testing = 1, - Alpha = 2, Beta = 3, - Normal = 4, - LTS = 5, // Long time surpport, 长期支持 - Stopped = 6, // Stopped surpport and updating, 停止更新与支持 - } - - /// - /// 运行架构 - /// - public enum Architecture - { - x86_32 = 0, - x86_64 = 1, - arm = 11, - long_arch = 21, - } - - /// - /// 主版本号 - /// - public ushort Major => majorVersion; - - /// - /// 副版本号 - /// - public ushort Minor => minorVersion; - - /// - /// 分支版本号 - /// - public ushort Branch => branchVersion; - - /// - /// 构建版本号 - /// - public ushort Build => buildVersion; - - /// - /// 获取版本号字符串 - /// - /// 前导字符串 - /// 后缀字符串 - /// 版本号字符串 - public string GetVersionText(string prefix = "v", string suffix = "") - { - return - $"{prefix}" + - $"{Major}.{Minor}.{Branch}.{Build}" + - $"{suffix}"; - } - - /// - /// 从字符串反序列化版本结构 - /// - /// 字符串 - /// 版本结构 - public static Version Parse(string version) - { - var regex = new Regex(RegexStrings.Version_Parse_STR); - var collection = regex.Matches(version); - - if (collection.Count > 1) - throw new Result("More than one version expression matched."); - else - { - foreach (Match match in collection.Cast()) - { - var parts = match.Value.Split('.'); - var result = new Version(); - - result.SetVersion( - ushort.Parse(parts[0]), - ushort.Parse(parts[1]), - ushort.Parse(parts[2]), - parts.Length == 4 ? - ushort.Parse(parts[3]) : (ushort)0 - ); - - return result; - } - throw new Result("No version expression matched."); - } - } -} diff --git a/README.md b/README.md index dd9117c..c082b13 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -

+

Common.BasicHelper Logo @@ -18,8 +18,69 @@ Via dotnet cli dotnet add package Common.BasicHelper ``` +# Samples + +We provide some samples in `Commong.BasicHelper.Samples` project. + +To run this project, just run commands: + +```shell +cd Common.BasicHelper.Samples +dotnet run +``` + +The output will looks like + +```plaintext +info: Microsoft.Hosting.Lifetime[14] + Now listening on: http://localhost: +info: Microsoft.Hosting.Lifetime[0] + Application started. Press Ctrl+C to shut down. +info: Microsoft.Hosting.Lifetime[0] + Hosting environment: Development +info: Microsoft.Hosting.Lifetime[0] + Content root path: +``` + +`` label is the port number of the server. + +Then you can visit `http://localhost:/swagger/index.html` to see the samples. + # Usage -building ... +## Extensions + +You can use follow namespace to use extensions: + +```CSharp +using Common.BasicHelper.Utils.Extensions; +``` + +Such as extensions in `QueueHelper`: + +```CSharp +var queue = new Queue() + .Push(1) + .Push(2) + .Pop() + .Push(3) + .Push(4) + .Pop() + .Push(5) + ; +queue.Dump(); // Result will be "3 4 5 " +``` + +And you can execute a string as a system command: + +```CSharp +"help".ExecuteAsCommand(); +``` + +And you can pass arguments through parameters `args`. + +More extensions can be find in our docs later. + +