1
0

Using native Convert from hex function for .NET 8

This commit is contained in:
2024-09-13 07:53:41 +02:00
parent df6763b99b
commit fb26e441a4
4 changed files with 43 additions and 35 deletions

View File

@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- .NET 8.0: `System.Net.IPNetwork` - .NET 8.0: `System.Net.IPNetwork`
- Moved `MessagePack` formatter extensions to own package `AMWD.Common.MessagePack` - Moved `MessagePack` formatter extensions to own package `AMWD.Common.MessagePack`
- `GetAlignedInterval()` (without Local/Utc) is now public accessible - `GetAlignedInterval()` (without Local/Utc) is now public accessible
- Using native `Convert.FromHexString` on .NET 8.0 on `HexToBytes` extension
### Removed ### Removed

View File

@@ -22,6 +22,8 @@ namespace System
public static class StringExtensions public static class StringExtensions
#endif #endif
{ {
private const string EmailRegex = @"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$";
/// <summary> /// <summary>
/// Converts a hex string into a byte array. /// Converts a hex string into a byte array.
/// </summary> /// </summary>
@@ -30,23 +32,28 @@ namespace System
/// <returns>The bytes.</returns> /// <returns>The bytes.</returns>
public static IEnumerable<byte> HexToBytes(this string hexString, string delimiter = "") public static IEnumerable<byte> HexToBytes(this string hexString, string delimiter = "")
{ {
if (string.IsNullOrWhiteSpace(hexString)) if (hexString == null)
yield break; throw new ArgumentNullException(nameof(hexString));
string str = string.IsNullOrEmpty(delimiter) ? hexString : hexString.Replace(delimiter, ""); string str = string.IsNullOrEmpty(delimiter)
if (str.Length % 2 == 1) ? hexString
yield break; : hexString.Replace(delimiter, "");
#if NET8_0_OR_GREATER #if NET8_0_OR_GREATER
if (InvalidHexCharRegex().IsMatch(str)) return Convert.FromHexString(str);
yield break;
#else #else
if (Regex.IsMatch(str, "[^0-9a-fA-F]", RegexOptions.Compiled)) if (Regex.IsMatch(str, "[^0-9a-fA-F]", RegexOptions.Compiled))
yield break; throw new FormatException("The input is not a valid hex string as it contains a non-hex character.");
#endif
for (int i = 0; i < str.Length; i += 2) if (str.Length % 2 != 0)
yield return Convert.ToByte(str.Substring(i, 2), 16); throw new FormatException("The input is not a valid hex string as its length is not a multiple of 2.");
byte[] bytes = new byte[str.Length / 2];
for (int i = 0; i < bytes.Length; i++)
bytes[i] = Convert.ToByte(str.Substring(i * 2, 2), 16);
return bytes;
#endif
} }
/// <summary> /// <summary>
@@ -193,8 +200,7 @@ namespace System
if (!ValidEmailRegex().IsMatch(emailAddress)) if (!ValidEmailRegex().IsMatch(emailAddress))
return false; return false;
#else #else
string emailRegex = @"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$"; if (!Regex.IsMatch(emailAddress, EmailRegex, RegexOptions.Compiled))
if (!Regex.IsMatch(emailAddress, emailRegex, RegexOptions.Compiled))
return false; return false;
#endif #endif
@@ -248,10 +254,7 @@ namespace System
=> sb.Append(value).Append(newLine); => sb.Append(value).Append(newLine);
#if NET8_0_OR_GREATER #if NET8_0_OR_GREATER
[GeneratedRegex("[^0-9a-fA-F]", RegexOptions.Compiled)] [GeneratedRegex(EmailRegex, RegexOptions.Compiled)]
private static partial Regex InvalidHexCharRegex();
[GeneratedRegex(@"^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$", RegexOptions.Compiled)]
private static partial Regex ValidEmailRegex(); private static partial Regex ValidEmailRegex();
#endif #endif
} }

View File

@@ -38,7 +38,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AMWD.NetRevisionTask" Version="1.2.0"> <PackageReference Include="AMWD.NetRevisionTask" Version="1.2.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@@ -8,6 +8,19 @@ namespace AMWD.Common.Tests.Extensions
[TestClass] [TestClass]
public class StringExtensionsTest public class StringExtensionsTest
{ {
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void ShouldThrowArgumentNullExceptionWhenNull()
{
// arrange
string hex = null;
// act
var bytes = hex.HexToBytes();
// assert - ArgumentNullException
}
[TestMethod] [TestMethod]
public void ShouldReturnEmptyList() public void ShouldReturnEmptyList()
{ {
@@ -22,28 +35,19 @@ namespace AMWD.Common.Tests.Extensions
Assert.IsFalse(bytes.Any()); Assert.IsFalse(bytes.Any());
} }
[TestMethod] [DataTestMethod]
public void ShouldReturnEmptyListWhenInvalid() [DataRow("aff", null)]
[DataRow("de:ad:be:e", ":")]
[DataRow("hell", "")]
[ExpectedException(typeof(FormatException))]
public void ShouldThrowFormatExceptionWhenInvalid(string hex, string delimiter)
{ {
// arrange // arrange
string hex1 = "aff";
string hex2 = "de:ad:be:e";
string hex3 = "hell";
// act // act
var bytes1 = hex1.HexToBytes(); var bytes = hex.HexToBytes(delimiter);
var bytes2 = hex2.HexToBytes(":");
var bytes3 = hex3.HexToBytes();
// assert // assert - FormatException
Assert.IsNotNull(bytes1);
Assert.IsFalse(bytes1.Any());
Assert.IsNotNull(bytes2);
Assert.IsFalse(bytes2.Any());
Assert.IsNotNull(bytes3);
Assert.IsFalse(bytes3.Any());
} }
[TestMethod] [TestMethod]