diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4638b9e..8a21db0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- .NET 8.0: `System.Net.IPNetwork`
- Moved `MessagePack` formatter extensions to own package `AMWD.Common.MessagePack`
- `GetAlignedInterval()` (without Local/Utc) is now public accessible
+- Using native `Convert.FromHexString` on .NET 8.0 on `HexToBytes` extension
### Removed
diff --git a/src/AMWD.Common/Extensions/StringExtensions.cs b/src/AMWD.Common/Extensions/StringExtensions.cs
index bb50e3a..4952ce4 100644
--- a/src/AMWD.Common/Extensions/StringExtensions.cs
+++ b/src/AMWD.Common/Extensions/StringExtensions.cs
@@ -22,6 +22,8 @@ namespace System
public static class StringExtensions
#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])?$";
+
///
/// Converts a hex string into a byte array.
///
@@ -30,23 +32,28 @@ namespace System
/// The bytes.
public static IEnumerable HexToBytes(this string hexString, string delimiter = "")
{
- if (string.IsNullOrWhiteSpace(hexString))
- yield break;
+ if (hexString == null)
+ throw new ArgumentNullException(nameof(hexString));
- string str = string.IsNullOrEmpty(delimiter) ? hexString : hexString.Replace(delimiter, "");
- if (str.Length % 2 == 1)
- yield break;
+ string str = string.IsNullOrEmpty(delimiter)
+ ? hexString
+ : hexString.Replace(delimiter, "");
#if NET8_0_OR_GREATER
- if (InvalidHexCharRegex().IsMatch(str))
- yield break;
+ return Convert.FromHexString(str);
#else
if (Regex.IsMatch(str, "[^0-9a-fA-F]", RegexOptions.Compiled))
- yield break;
-#endif
+ throw new FormatException("The input is not a valid hex string as it contains a non-hex character.");
- for (int i = 0; i < str.Length; i += 2)
- yield return Convert.ToByte(str.Substring(i, 2), 16);
+ if (str.Length % 2 != 0)
+ 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
}
///
@@ -193,8 +200,7 @@ namespace System
if (!ValidEmailRegex().IsMatch(emailAddress))
return false;
#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;
#endif
@@ -248,10 +254,7 @@ namespace System
=> sb.Append(value).Append(newLine);
#if NET8_0_OR_GREATER
- [GeneratedRegex("[^0-9a-fA-F]", 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)]
+ [GeneratedRegex(EmailRegex, RegexOptions.Compiled)]
private static partial Regex ValidEmailRegex();
#endif
}
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 21669d9..0c023be 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -38,7 +38,7 @@
-
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
diff --git a/test/AMWD.Common.Tests/Extensions/StringExtensionsTest.cs b/test/AMWD.Common.Tests/Extensions/StringExtensionsTest.cs
index 49fbfe2..87f718a 100644
--- a/test/AMWD.Common.Tests/Extensions/StringExtensionsTest.cs
+++ b/test/AMWD.Common.Tests/Extensions/StringExtensionsTest.cs
@@ -8,6 +8,19 @@ namespace AMWD.Common.Tests.Extensions
[TestClass]
public class StringExtensionsTest
{
+ [TestMethod]
+ [ExpectedException(typeof(ArgumentNullException))]
+ public void ShouldThrowArgumentNullExceptionWhenNull()
+ {
+ // arrange
+ string hex = null;
+
+ // act
+ var bytes = hex.HexToBytes();
+
+ // assert - ArgumentNullException
+ }
+
[TestMethod]
public void ShouldReturnEmptyList()
{
@@ -22,28 +35,19 @@ namespace AMWD.Common.Tests.Extensions
Assert.IsFalse(bytes.Any());
}
- [TestMethod]
- public void ShouldReturnEmptyListWhenInvalid()
+ [DataTestMethod]
+ [DataRow("aff", null)]
+ [DataRow("de:ad:be:e", ":")]
+ [DataRow("hell", "")]
+ [ExpectedException(typeof(FormatException))]
+ public void ShouldThrowFormatExceptionWhenInvalid(string hex, string delimiter)
{
// arrange
- string hex1 = "aff";
- string hex2 = "de:ad:be:e";
- string hex3 = "hell";
// act
- var bytes1 = hex1.HexToBytes();
- var bytes2 = hex2.HexToBytes(":");
- var bytes3 = hex3.HexToBytes();
+ var bytes = hex.HexToBytes(delimiter);
- // assert
- Assert.IsNotNull(bytes1);
- Assert.IsFalse(bytes1.Any());
-
- Assert.IsNotNull(bytes2);
- Assert.IsFalse(bytes2.Any());
-
- Assert.IsNotNull(bytes3);
- Assert.IsFalse(bytes3.Any());
+ // assert - FormatException
}
[TestMethod]