From 788c09fb0b5852729f2e810874e8b5f7cb452627 Mon Sep 17 00:00:00 2001 From: amsga <49681949+amsga@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:54:53 +0800 Subject: [PATCH] Changed to target multiple frameworks. Added optimisations based on each framework's capability. --- .github/workflows/dotnet.yml | 26 +++++++++---------- .../TensionDev.UUID.Tests.csproj | 10 +++---- TensionDev.UUID/TensionDev.UUID.csproj | 8 +++--- TensionDev.UUID/UUIDv1.cs | 22 ++++++++++++++++ TensionDev.UUID/UUIDv3.cs | 4 +++ TensionDev.UUID/UUIDv4.cs | 8 ++++++ TensionDev.UUID/UUIDv5.cs | 4 +++ TensionDev.UUID/UUIDv6.cs | 20 ++++++++++++++ TensionDev.UUID/UUIDv7.cs | 23 ++++++++++++++++ TensionDev.UUID/Uuid.cs | 16 ++++++------ 10 files changed, 110 insertions(+), 31 deletions(-) diff --git a/.github/workflows/dotnet.yml b/.github/workflows/dotnet.yml index 6d67f7e..c1db74e 100644 --- a/.github/workflows/dotnet.yml +++ b/.github/workflows/dotnet.yml @@ -13,31 +13,31 @@ jobs: strategy: matrix: - dotnet: [ '8.0.x' ] + dotnet: [ '10.0.x' ] name: .NET ${{ matrix.dotnet }} steps: - - name: Set up JDK 17 - uses: actions/setup-java@v4 + - name: Set up JDK 25 + uses: actions/setup-java@v6 with: - java-version: 17 + java-version: 25 distribution: 'zulu' # Alternative distribution options are available. - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v6 with: dotnet-version: ${{ matrix.dotnet }} - name: Cache SonarQube Cloud packages - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: ~\sonar\cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache SonarQube Cloud scanner id: cache-sonar-scanner - uses: actions/cache@v4 + uses: actions/cache@v5 with: path: .\.sonar\scanner key: ${{ runner.os }}-sonar-scanner @@ -58,7 +58,7 @@ jobs: - name: Build run: dotnet build --no-restore - name: Test - run: dotnet test --no-build --verbosity normal --collect "XPlat Code Coverage;Format=opencover" + run: dotnet run --project TensionDev.UUID.Tests/TensionDev.UUID.Tests.csproj --no-build -- --coverlet --coverlet-output-format opencover - name: SonarCloudAnalyze env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any @@ -69,7 +69,7 @@ jobs: strategy: matrix: - dotnet: [ '8.0.x' ] + dotnet: [ '10.0.x' ] os: [macos-latest, ubuntu-latest, windows-latest] runs-on: ${{ matrix.os }} @@ -77,11 +77,11 @@ jobs: name: .NET ${{ matrix.dotnet }} on ${{ matrix.os }} steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v7 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Setup .NET - uses: actions/setup-dotnet@v4 + uses: actions/setup-dotnet@v6 with: dotnet-version: ${{ matrix.dotnet }} - name: Restore dependencies @@ -89,4 +89,4 @@ jobs: - name: Build run: dotnet build --no-restore - name: Test - run: dotnet test --no-build --verbosity normal --collect "XPlat Code Coverage;Format=opencover" + run: dotnet run --project TensionDev.UUID.Tests/TensionDev.UUID.Tests.csproj --no-build -- --coverlet --coverlet-output-format opencover diff --git a/TensionDev.UUID.Tests/TensionDev.UUID.Tests.csproj b/TensionDev.UUID.Tests/TensionDev.UUID.Tests.csproj index a3a7ba1..07825c9 100644 --- a/TensionDev.UUID.Tests/TensionDev.UUID.Tests.csproj +++ b/TensionDev.UUID.Tests/TensionDev.UUID.Tests.csproj @@ -1,22 +1,20 @@ - net8.0;net10.0 + net10.0 false + true + - all runtime; build; native; contentfiles; analyzers; buildtransitive - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/TensionDev.UUID/TensionDev.UUID.csproj b/TensionDev.UUID/TensionDev.UUID.csproj index 4b03f88..d042ac5 100644 --- a/TensionDev.UUID/TensionDev.UUID.csproj +++ b/TensionDev.UUID/TensionDev.UUID.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netstandard2.0;netcoreapp3.1;net6.0;net8.0;net10.0 TensionDev.UUID TensionDev.UUID all @@ -10,15 +10,15 @@ true true TensionDev.UUID - 2.4.0 + 2.5.0 TensionDev amsga TensionDev TensionDev.UUID TensionDev.UUID is a .NET library that supports multiple UUID versions (v1, v3, v4, v5, v6, v7) with strict RFC compliance. Copyright (c) TensionDev 2021 - 2026 Apache-2.0 - https://github.com/TensionDev/UUIDUtil - https://github.com/TensionDev/UUIDUtil + https://github.com/TensionDev/UUID + https://github.com/TensionDev/UUID git UUID GUID Change in license to Apache License 2.0. diff --git a/TensionDev.UUID/UUIDv1.cs b/TensionDev.UUID/UUIDv1.cs index 316dbc6..c4ea3df 100644 --- a/TensionDev.UUID/UUIDv1.cs +++ b/TensionDev.UUID/UUIDv1.cs @@ -28,8 +28,13 @@ public static class UUIDv1 private static Int32 s_clock = Int32.MinValue; private static readonly DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc); +#if NET9_0_OR_GREATER + private static readonly System.Threading.Lock s_initLock = new System.Threading.Lock(); + private static readonly System.Threading.Lock s_clockLock = new System.Threading.Lock(); +#else private static readonly Object s_initLock = new Object(); private static readonly Object s_clockLock = new Object(); +#endif /// /// Initialises a new GUID/UUID based on Version 1 (date-time and MAC address) @@ -140,6 +145,14 @@ public static Byte[] GetNodeID() } if (s_physicalAddress.Equals(System.Net.NetworkInformation.PhysicalAddress.None)) { +#if NET6_0_OR_GREATER + // Fallback to random + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + Byte[] fakeNode = new Byte[6]; + randomNumberGenerator.GetBytes(fakeNode); + fakeNode[0] = (Byte)(fakeNode[0] | 0x01); + s_physicalAddress = new System.Net.NetworkInformation.PhysicalAddress(fakeNode); +#else // Fallback to random using (var cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { @@ -148,6 +161,7 @@ public static Byte[] GetNodeID() fakeNode[0] = (Byte)(fakeNode[0] | 0x01); s_physicalAddress = new System.Net.NetworkInformation.PhysicalAddress(fakeNode); } +#endif } } @@ -165,6 +179,13 @@ public static Byte[] GetClockSequence() { if (s_clock < 0) { +#if NET6_0_OR_GREATER + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + Byte[] clockInit = new Byte[4]; + randomNumberGenerator.GetBytes(clockInit); + s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF; + s_clock |= 0x8000; +#else using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { Byte[] clockInit = new Byte[4]; @@ -172,6 +193,7 @@ public static Byte[] GetClockSequence() s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF; s_clock |= 0x8000; } +#endif } } diff --git a/TensionDev.UUID/UUIDv3.cs b/TensionDev.UUID/UUIDv3.cs index 8171bcb..a20f6dc 100644 --- a/TensionDev.UUID/UUIDv3.cs +++ b/TensionDev.UUID/UUIDv3.cs @@ -39,10 +39,14 @@ public static Uuid NewUUIDv3(Uuid nameSpace, String name) Buffer.BlockCopy(nArray, 0, buffer, nsArray.Length, nArray.Length); Byte[] hash; +#if NET6_0_OR_GREATER + hash = MD5.HashData(buffer); +#else using (MD5 md5 = MD5.Create()) { hash = md5.ComputeHash(buffer); } +#endif Byte[] hex = new Byte[16]; diff --git a/TensionDev.UUID/UUIDv4.cs b/TensionDev.UUID/UUIDv4.cs index ec5ee6f..d5abb30 100644 --- a/TensionDev.UUID/UUIDv4.cs +++ b/TensionDev.UUID/UUIDv4.cs @@ -33,12 +33,20 @@ public static Uuid NewUUIDv4() Byte[] clockSequence = new Byte[2]; Byte[] nodeID = new Byte[6]; +#if NET6_0_OR_GREATER + // Fallback to random + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + randomNumberGenerator.GetBytes(time); + randomNumberGenerator.GetBytes(clockSequence); + randomNumberGenerator.GetBytes(nodeID); +#else using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { cryptoServiceProvider.GetBytes(time); cryptoServiceProvider.GetBytes(clockSequence); cryptoServiceProvider.GetBytes(nodeID); } +#endif Byte[] hex = new Byte[16]; diff --git a/TensionDev.UUID/UUIDv5.cs b/TensionDev.UUID/UUIDv5.cs index ee67c6d..430a39a 100644 --- a/TensionDev.UUID/UUIDv5.cs +++ b/TensionDev.UUID/UUIDv5.cs @@ -39,10 +39,14 @@ public static Uuid NewUUIDv5(Uuid nameSpace, String name) Buffer.BlockCopy(nArray, 0, buffer, nsArray.Length, nArray.Length); Byte[] hash; +#if NET6_0_OR_GREATER + hash = SHA1.HashData(buffer); +#else using (SHA1 sha1 = SHA1.Create()) { hash = sha1.ComputeHash(buffer); } +#endif Byte[] hex = new Byte[16]; diff --git a/TensionDev.UUID/UUIDv6.cs b/TensionDev.UUID/UUIDv6.cs index bc028ef..9c98ac0 100644 --- a/TensionDev.UUID/UUIDv6.cs +++ b/TensionDev.UUID/UUIDv6.cs @@ -26,8 +26,13 @@ public static class UUIDv6 private static Int32 s_clock = Int32.MinValue; private static readonly DateTime s_epoch = new DateTime(1582, 10, 15, 0, 0, 0, DateTimeKind.Utc); +#if NET9_0_OR_GREATER + private static readonly System.Threading.Lock s_initLock = new System.Threading.Lock(); + private static readonly System.Threading.Lock s_clockLock = new System.Threading.Lock(); +#else private static readonly Object s_initLock = new Object(); private static readonly Object s_clockLock = new Object(); +#endif /// /// Initialises a new GUID/UUID based on Version 6 (date-time) @@ -123,12 +128,19 @@ public static Uuid NewUUIDv6(DateTime dateTime, Byte[] clockSequence, Byte[] nod /// A byte-array representing the 48-bit Node ID public static Byte[] GetNodeID() { +#if NET6_0_OR_GREATER + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + Byte[] fakeNode = new Byte[6]; + randomNumberGenerator.GetBytes(fakeNode); + return fakeNode; +#else using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { Byte[] fakeNode = new Byte[6]; cryptoServiceProvider.GetBytes(fakeNode); return fakeNode; } +#endif } /// @@ -142,6 +154,13 @@ public static Byte[] GetClockSequence() { if (s_clock < 0) { +#if NET6_0_OR_GREATER + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + Byte[] clockInit = new Byte[4]; + randomNumberGenerator.GetBytes(clockInit); + s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF; + s_clock |= 0x8000; +#else using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { Byte[] clockInit = new Byte[4]; @@ -149,6 +168,7 @@ public static Byte[] GetClockSequence() s_clock = BitConverter.ToInt32(clockInit, 0) & 0x3FFF; s_clock |= 0x8000; } +#endif } } diff --git a/TensionDev.UUID/UUIDv7.cs b/TensionDev.UUID/UUIDv7.cs index 123a9e8..4aa2bea 100644 --- a/TensionDev.UUID/UUIDv7.cs +++ b/TensionDev.UUID/UUIDv7.cs @@ -24,10 +24,19 @@ namespace TensionDev.UUID /// public static class UUIDv7 { +#if NETCOREAPP2_1_OR_GREATER + private static readonly DateTime s_epoch = DateTime.UnixEpoch; +#else private static readonly DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); +#endif private static UInt16 s_counter = 0; + +#if NET9_0_OR_GREATER + private static readonly System.Threading.Lock s_counterLock = new System.Threading.Lock(); +#else private static readonly Object s_counterLock = new Object(); +#endif /// /// The method of generating the clock sequence and Node ID. @@ -143,12 +152,19 @@ public static Uuid NewUUIDv7(DateTime dateTime, Byte[] randomA, Byte[] randomB) /// A byte-array representing the 16-bit rand_a public static Byte[] GetRandomA() { +#if NET6_0_OR_GREATER + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + Byte[] fakeNode = new Byte[2]; + randomNumberGenerator.GetBytes(fakeNode); + return fakeNode; +#else using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { Byte[] fakeNode = new Byte[2]; cryptoServiceProvider.GetBytes(fakeNode); return fakeNode; } +#endif } /// @@ -197,12 +213,19 @@ public static Byte[] GetIncreasedClockPrecisionA(DateTime currentDateTime) /// A byte-array representing the 64-bit rand_b public static Byte[] GetRandomB() { +#if NET6_0_OR_GREATER + using var randomNumberGenerator = System.Security.Cryptography.RandomNumberGenerator.Create(); + Byte[] fakeNode = new Byte[8]; + randomNumberGenerator.GetBytes(fakeNode); + return fakeNode; +#else using (System.Security.Cryptography.RNGCryptoServiceProvider cryptoServiceProvider = new System.Security.Cryptography.RNGCryptoServiceProvider()) { Byte[] fakeNode = new Byte[8]; cryptoServiceProvider.GetBytes(fakeNode); return fakeNode; } +#endif } /// diff --git a/TensionDev.UUID/Uuid.cs b/TensionDev.UUID/Uuid.cs index 41bd5db..c192797 100644 --- a/TensionDev.UUID/Uuid.cs +++ b/TensionDev.UUID/Uuid.cs @@ -446,14 +446,14 @@ private string ToStringCannonical() // RFC 4122 big-endian layout sb.AppendFormat(FOUR_BYTE_HEX_FORMAT_STRING, _time_low); // 8 hex digits - sb.Append("-"); + sb.Append('-'); sb.AppendFormat(TWO_BYTE_HEX_FORMAT_STRING, _time_mid); // 4 hex digits - sb.Append("-"); + sb.Append('-'); sb.AppendFormat(TWO_BYTE_HEX_FORMAT_STRING, _time_hi_and_version); // 4 hex digits - sb.Append("-"); + sb.Append('-'); sb.AppendFormat(ONE_BYTE_HEX_FORMAT_STRING, _clock_seq_hi_and_reserved); sb.AppendFormat(ONE_BYTE_HEX_FORMAT_STRING, _clock_seq_low); - sb.Append("-"); + sb.Append('-'); foreach (byte b in _node) sb.AppendFormat(ONE_BYTE_HEX_FORMAT_STRING, b); @@ -482,9 +482,9 @@ private string ToStringParenthesis() { StringBuilder sb = new StringBuilder(); - sb.Append("("); + sb.Append('('); sb.Append(ToStringCannonical()); - sb.Append(")"); + sb.Append(')'); return sb.ToString(); } @@ -493,9 +493,9 @@ private string ToStringBraces() { StringBuilder sb = new StringBuilder(); - sb.Append("{"); + sb.Append('{'); sb.Append(ToStringCannonical()); - sb.Append("}"); + sb.Append('}'); return sb.ToString(); }