diff --git a/.editorconfig b/.editorconfig
index 6c110f0..694a60f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -287,4 +287,13 @@ dotnet_naming_style.pascal_case.word_separator =
dotnet_naming_style.pascal_case.capitalization = pascal_case
# IDE0290: Use primary constructor
-dotnet_diagnostic.IDE0290.severity = none
\ No newline at end of file
+dotnet_diagnostic.IDE0290.severity = none
+
+# MA0017: Abstract types should not have public or internal constructors
+dotnet_diagnostic.MA0017.severity = none
+
+# MA0018: Do not declare static members on generic types (deprecated; use CA1000 instead)
+dotnet_diagnostic.MA0018.severity = none
+
+# MA0154: Use langword in XML comment
+dotnet_diagnostic.MA0154.severity = none
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 7653d0c..7408378 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -18,17 +18,19 @@ jobs:
steps:
- name: Cancel previous builds in PR
- uses: styfle/cancel-workflow-action@0.9.1
+ uses: styfle/cancel-workflow-action@0.12.1
- - name: 'Checkoud Code'
+ - name: 'Checkout Code'
uses: actions/checkout@v4
with:
fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
- name: 'Install .NET SDK'
- uses: actions/setup-dotnet@v3
+ uses: actions/setup-dotnet@v4
with:
global-json-file: ./global.json
+ #dotnet-version: '9.x'
+ #dotnet-quality: 'preview'
- name: Versioning
uses: dotnet/nbgv@master
diff --git a/Directory.Build.props b/Directory.Build.props
index 1d5eead..cd1bbc4 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -27,7 +27,7 @@
- net7.0;net8.0
+ net7.0;net8.0;net9.0
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 9544ddf..a23f179 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -16,6 +16,10 @@
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
diff --git a/global.json b/global.json
index 9da8d87..a28e9c5 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,5 @@
{
"sdk": {
- "version": "8.0.100"
+ "version": "9.0.100-preview.3.24204.13"
}
}
-
diff --git a/src/StrongOf.AspNetCore/StrongOf.AspNetCore.csproj b/src/StrongOf.AspNetCore/StrongOf.AspNetCore.csproj
index f9cf339..a90692f 100644
--- a/src/StrongOf.AspNetCore/StrongOf.AspNetCore.csproj
+++ b/src/StrongOf.AspNetCore/StrongOf.AspNetCore.csproj
@@ -1,5 +1,12 @@
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
true
readme.md
diff --git a/src/StrongOf.FluentValidation/StrongOf.FluentValidation.csproj b/src/StrongOf.FluentValidation/StrongOf.FluentValidation.csproj
index fe168c4..4eb8ca7 100644
--- a/src/StrongOf.FluentValidation/StrongOf.FluentValidation.csproj
+++ b/src/StrongOf.FluentValidation/StrongOf.FluentValidation.csproj
@@ -1,5 +1,12 @@
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
true
readme.md
@@ -16,6 +23,6 @@
-
+
diff --git a/src/StrongOf.FluentValidation/StrongStringValidators.cs b/src/StrongOf.FluentValidation/StrongStringValidators.cs
index 8b648df..b6dfdaf 100644
--- a/src/StrongOf.FluentValidation/StrongStringValidators.cs
+++ b/src/StrongOf.FluentValidation/StrongStringValidators.cs
@@ -46,7 +46,7 @@ public static class StrongStringValidators
/// The rule builder options.
public static IRuleBuilderOptions HasMaximumLength(this IRuleBuilder rule, int maxLength)
where TStrong : StrongString
- => rule.Must(content => content?.Value is null ? true : content.Value.Length <= maxLength);
+ => rule.Must(content => content?.Value is null || content.Value.Length <= maxLength);
///
/// Validates that the strong string matches a regular expression.
@@ -94,15 +94,20 @@ public static class StrongStringValidators
}
///
- /// Validates that the strong string only contains allowed characters.
+ /// Specifies that the value being validated must only contain characters from the specified collection.
///
- /// The type of the object being validated.
- /// The type of the strong string.
+ /// The type of the parent object being validated.
+ /// The type of the strong string being validated.
/// The rule builder.
- /// The set of allowed characters.
- /// The message pattern to use if the validation fails.
+ /// The collection of allowed characters.
+ /// The pattern used to format the error message if validation fails.
+ /// An optional that supplies culture-specific formatting information.
/// The rule builder options.
- public static IRuleBuilderOptionsConditions AllowedChars(this IRuleBuilder rule, HashSet chars, string messagePattern)
+ ///
+ /// This method adds a custom validation rule to the rule builder that checks if the value being validated contains only characters from the specified collection.
+ /// If the validation fails, an error message is added to the validation context using the provided message pattern.
+ ///
+ public static IRuleBuilderOptionsConditions AllowedChars(this IRuleBuilder rule, ICollection chars, string messagePattern, IFormatProvider? formatProvider = null)
where TStrong : StrongString
{
return rule.Custom((topic, context) =>
@@ -111,7 +116,7 @@ public static class StrongStringValidators
{
if (strong.ContainsInvalidChars(chars, out ICollection? invalidChars))
{
- context.AddFailure(string.Format(messagePattern, string.Concat(invalidChars)));
+ context.AddFailure(string.Format(formatProvider, messagePattern, string.Concat(invalidChars)));
}
}
});
diff --git a/src/StrongOf.Json/StrongDateTimeOffsetJsonConverter.cs b/src/StrongOf.Json/StrongDateTimeOffsetJsonConverter.cs
index ab03cf0..11423be 100644
--- a/src/StrongOf.Json/StrongDateTimeOffsetJsonConverter.cs
+++ b/src/StrongOf.Json/StrongDateTimeOffsetJsonConverter.cs
@@ -1,4 +1,5 @@
-using System.Text.Json;
+using System.Globalization;
+using System.Text.Json;
using System.Text.Json.Serialization;
namespace StrongOf.Json;
@@ -35,5 +36,5 @@ public class StrongDateTimeOffsetJsonConverter : JsonConverter
/// The value to write.
/// Options to control the serializer behavior during writing.
public override void Write(Utf8JsonWriter writer, TStrong strong, JsonSerializerOptions options)
- => writer.WriteStringValue(strong.Value.ToString());
+ => writer.WriteStringValue(strong.Value.ToString(CultureInfo.InvariantCulture));
}
diff --git a/src/StrongOf.Json/StrongInt32JsonConverter.cs b/src/StrongOf.Json/StrongInt32JsonConverter.cs
index 6715b42..257fdd8 100644
--- a/src/StrongOf.Json/StrongInt32JsonConverter.cs
+++ b/src/StrongOf.Json/StrongInt32JsonConverter.cs
@@ -1,4 +1,5 @@
-using System.Text.Json;
+using System.Globalization;
+using System.Text.Json;
using System.Text.Json.Serialization;
namespace StrongOf.Json;
@@ -35,5 +36,5 @@ public class StrongInt32JsonConverter : JsonConverter
/// The value to write.
/// Options to control the serializer behavior during writing.
public override void Write(Utf8JsonWriter writer, TStrong strong, JsonSerializerOptions options)
- => writer.WriteStringValue(strong.Value.ToString());
+ => writer.WriteStringValue(strong.Value.ToString(CultureInfo.InvariantCulture));
}
diff --git a/src/StrongOf.Json/StrongInt64JsonConverter.cs b/src/StrongOf.Json/StrongInt64JsonConverter.cs
index 65d84b9..3870e3c 100644
--- a/src/StrongOf.Json/StrongInt64JsonConverter.cs
+++ b/src/StrongOf.Json/StrongInt64JsonConverter.cs
@@ -1,4 +1,5 @@
-using System.Text.Json;
+using System.Globalization;
+using System.Text.Json;
using System.Text.Json.Serialization;
namespace StrongOf.Json;
@@ -35,5 +36,5 @@ public class StrongInt64JsonConverter : JsonConverter
/// The value to write.
/// Options to control the serializer behavior during writing.
public override void Write(Utf8JsonWriter writer, TStrong strong, JsonSerializerOptions options)
- => writer.WriteStringValue(strong.Value.ToString());
+ => writer.WriteStringValue(strong.Value.ToString(CultureInfo.InvariantCulture));
}
diff --git a/src/StrongOf.Json/StrongOf.Json.csproj b/src/StrongOf.Json/StrongOf.Json.csproj
index 7be2ecb..065027c 100644
--- a/src/StrongOf.Json/StrongOf.Json.csproj
+++ b/src/StrongOf.Json/StrongOf.Json.csproj
@@ -1,5 +1,12 @@
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
true
readme.md
diff --git a/src/StrongOf.Json/StrongOfJsonConverter.cs b/src/StrongOf.Json/StrongStringJsonConverter.cs
similarity index 100%
rename from src/StrongOf.Json/StrongOfJsonConverter.cs
rename to src/StrongOf.Json/StrongStringJsonConverter.cs
diff --git a/src/StrongOf/StrongChar.Operators.cs b/src/StrongOf/StrongChar.Operators.cs
new file mode 100644
index 0000000..e172136
--- /dev/null
+++ b/src/StrongOf/StrongChar.Operators.cs
@@ -0,0 +1,177 @@
+namespace StrongOf;
+
+public abstract partial class StrongChar
+{
+ ///
+ /// Determines whether two specified instances of StrongChar are equal.
+ ///
+ /// The first instance to compare.
+ /// The object to compare.
+ /// True if strong and value represent the same char; otherwise, false.
+ public static bool operator ==(StrongChar? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is char charValue)
+ {
+ return strong.Value == charValue;
+ }
+
+ if (other is StrongChar otherStrong)
+ {
+ return strong.Value == otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether two specified instances of StrongChar are not equal.
+ ///
+ /// The first instance to compare.
+ /// The object to compare.
+ /// True if strong and other do not represent the same char; otherwise, false.
+ public static bool operator !=(StrongChar? strong, object? other)
+ {
+ return (strong == other) is false;
+ }
+
+ ///
+ /// Determines whether a object is less than another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is less than the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a char, the method compares the value of with the char value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+ public static bool operator <(StrongChar? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is char charValue)
+ {
+ return strong.Value < charValue;
+ }
+
+ if (other is StrongChar otherStrong)
+ {
+ return strong.Value < otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is greater than another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is greater than the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a char, the method compares the value of with the char value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+ public static bool operator >(StrongChar? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is char charValue)
+ {
+ return strong.Value > charValue;
+ }
+
+ if (other is StrongChar otherStrong)
+ {
+ return strong.Value > otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is less than or equal to another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is less than or equal to the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a char, the method compares the value of with the char value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+ public static bool operator <=(StrongChar? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is char charValue)
+ {
+ return strong.Value <= charValue;
+ }
+
+ if (other is StrongChar otherStrong)
+ {
+ return strong.Value <= otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is greater than or equal to another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is greater than or equal to the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a char, the method compares the value of with the char value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+ public static bool operator >=(StrongChar? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is char charValue)
+ {
+ return strong.Value >= charValue;
+ }
+
+ if (other is StrongChar otherStrong)
+ {
+ return strong.Value >= otherStrong.Value;
+ }
+
+ return false;
+ }
+}
diff --git a/src/StrongOf/StrongChar.cs b/src/StrongOf/StrongChar.cs
index 6591f13..b8fb7ea 100644
--- a/src/StrongOf/StrongChar.cs
+++ b/src/StrongOf/StrongChar.cs
@@ -6,7 +6,8 @@ namespace StrongOf;
/// Represents a strongly typed character.
///
/// The type of the strong character.
-public abstract class StrongChar(char Value) : StrongOf(Value), IComparable, IStrongChar
+public abstract partial class StrongChar(char Value)
+ : StrongOf(Value), IComparable, IStrongChar
where TStrong : StrongChar
{
///
@@ -48,7 +49,7 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
@@ -69,45 +70,6 @@ public static bool TryParse(string content, [NotNullWhen(true)] out TStrong? str
return false;
}
- // Operators
-
- ///
- /// Determines whether two specified instances of StrongChar are equal.
- ///
- /// The first instance to compare.
- /// The object to compare.
- /// True if strong and value represent the same char; otherwise, false.
- public static bool operator ==(StrongChar? strong, object? other)
- {
- if (strong is null)
- {
- return other is null;
- }
-
- if (other is char charValue)
- {
- return strong.Value == charValue;
- }
-
- if (other is StrongChar otherStrong)
- {
- return strong.Value == otherStrong.Value;
- }
-
- return false;
- }
-
- ///
- /// Determines whether two specified instances of StrongChar are not equal.
- ///
- /// The first instance to compare.
- /// The object to compare.
- /// True if strong and other do not represent the same char; otherwise, false.
- public static bool operator !=(StrongChar? strong, object? other)
- {
- return (strong == other) is false;
- }
-
// Equals
///
diff --git a/src/StrongOf/StrongDateTime.Operators.cs b/src/StrongOf/StrongDateTime.Operators.cs
index 5cc267a..8e6b143 100644
--- a/src/StrongOf/StrongDateTime.Operators.cs
+++ b/src/StrongOf/StrongDateTime.Operators.cs
@@ -86,7 +86,7 @@ public abstract partial class StrongDateTime
if (other is DateTimeOffset dtoValue)
{
- return strong.Value < dtoValue;
+ return strong.Value < dtoValue.Date;
}
return false;
@@ -112,7 +112,7 @@ public abstract partial class StrongDateTime
if (other is DateTimeOffset dtoValue)
{
- return strong.Value > dtoValue;
+ return strong.Value > dtoValue.Date;
}
return false;
@@ -138,7 +138,7 @@ public abstract partial class StrongDateTime
if (other is DateTimeOffset dtoValue)
{
- return strong.Value <= dtoValue;
+ return strong.Value <= dtoValue.Date;
}
return false;
@@ -164,7 +164,7 @@ public abstract partial class StrongDateTime
if (other is DateTimeOffset dtoValue)
{
- return strong.Value >= dtoValue;
+ return strong.Value >= dtoValue.Date;
}
return false;
diff --git a/src/StrongOf/StrongDateTime.cs b/src/StrongOf/StrongDateTime.cs
index 0d74f40..d6a1a24 100644
--- a/src/StrongOf/StrongDateTime.cs
+++ b/src/StrongOf/StrongDateTime.cs
@@ -8,7 +8,8 @@ namespace StrongOf;
///
/// The type of the strong DateTime.
/// "The DateTime type has some design flaws. Please migrate to DateTimeOffset."
-public abstract partial class StrongDateTime(DateTime Value) : StrongOf(Value), IComparable, IStrongDateTime
+public abstract partial class StrongDateTime(DateTime Value)
+ : StrongOf(Value), IComparable, IStrongDateTime
where TStrong : StrongDateTime
{
///
@@ -73,7 +74,7 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
@@ -84,7 +85,7 @@ public int CompareTo(object? other)
/// True if content was converted successfully; otherwise, false.
public static bool TryParseIso8601(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong)
{
- if (TryParseExact(content, "o", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal, out strong))
+ if (TryParse(content, CultureInfo.InvariantCulture, out strong))
{
return true;
}
@@ -115,14 +116,15 @@ public static bool TryParseExact(ReadOnlySpan content, string format, IFor
}
///
- /// Tries to parse an DateTime from a ReadOnlySpan of char and returns a value that indicates whether the operation succeeded.
+ /// Tries to parse the specified content into a object.
///
- /// A ReadOnlySpan of char containing an DateTime to convert.
- /// When this method returns, contains the DateTime value equivalent to the DateTime contained in content, if the conversion succeeded, or null if the conversion failed.
- /// True if content was converted successfully; otherwise, false.
- public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong)
+ /// The content to parse.
+ /// When this method returns, contains the parsed value if the parsing succeeded, or null if the parsing failed. The parsing is case-sensitive.
+ /// An optional that supplies culture-specific formatting information.
+ /// true if the parsing was successful; otherwise, false.
+ public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong, IFormatProvider? formatProvider = null)
{
- if (DateTime.TryParse(content, out DateTime value))
+ if (DateTime.TryParse(content, formatProvider, out DateTime value))
{
strong = From(value);
return true;
diff --git a/src/StrongOf/StrongDateTimeOffset.Operators.cs b/src/StrongOf/StrongDateTimeOffset.Operators.cs
index 3027483..14a9358 100644
--- a/src/StrongOf/StrongDateTimeOffset.Operators.cs
+++ b/src/StrongOf/StrongDateTimeOffset.Operators.cs
@@ -59,7 +59,7 @@ public abstract partial class StrongDateTimeOffset
if (other is DateTime dtValue)
{
- return strong.Value < dtValue;
+ return strong.Value < new DateTimeOffset(dtValue);
}
return false;
@@ -85,7 +85,7 @@ public abstract partial class StrongDateTimeOffset
if (other is DateTime dtValue)
{
- return strong.Value > dtValue;
+ return strong.Value > new DateTimeOffset(dtValue);
}
return false;
@@ -111,7 +111,7 @@ public abstract partial class StrongDateTimeOffset
if (other is DateTime dtValue)
{
- return strong.Value <= dtValue;
+ return strong.Value <= new DateTimeOffset(dtValue);
}
return false;
@@ -137,7 +137,7 @@ public abstract partial class StrongDateTimeOffset
if (other is DateTime dtValue)
{
- return strong.Value >= dtValue;
+ return strong.Value >= new DateTimeOffset(dtValue);
}
return false;
diff --git a/src/StrongOf/StrongDateTimeOffset.cs b/src/StrongOf/StrongDateTimeOffset.cs
index 080a3b2..99c7e99 100644
--- a/src/StrongOf/StrongDateTimeOffset.cs
+++ b/src/StrongOf/StrongDateTimeOffset.cs
@@ -77,7 +77,7 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
@@ -119,14 +119,15 @@ public static bool TryParseExact(ReadOnlySpan content, string format, IFor
}
///
- /// Tries to parse a DateTimeOffset from a ReadOnlySpan of char and returns a value that indicates whether the operation succeeded.
+ /// Tries to parse the specified content into a object.
///
- /// A ReadOnlySpan of char containing a DateTimeOffset to convert.
- /// When this method returns, contains the DateTimeOffset value equivalent to the DateTimeOffset contained in content, if the conversion succeeded, or null if the conversion failed.
- /// True if content was converted successfully; otherwise, false.
- public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong)
+ /// The content to parse.
+ /// When this method returns, contains the parsed value if the parsing succeeded, or null if the parsing failed. The parsing is case-sensitive.
+ /// An optional that supplies culture-specific formatting information.
+ /// true if the parsing was successful; otherwise, false.
+ public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong, IFormatProvider? formatProvider = null)
{
- if (DateTimeOffset.TryParse(content, out DateTimeOffset value))
+ if (DateTimeOffset.TryParse(content, formatProvider, out DateTimeOffset value))
{
strong = From(value);
return true;
diff --git a/src/StrongOf/StrongDecimal.Operators.cs b/src/StrongOf/StrongDecimal.Operators.cs
new file mode 100644
index 0000000..337dd03
--- /dev/null
+++ b/src/StrongOf/StrongDecimal.Operators.cs
@@ -0,0 +1,217 @@
+namespace StrongOf;
+
+public abstract partial class StrongDecimal
+{
+ ///
+ /// Determines whether two specified instances of StrongDecimal are equal.
+ ///
+ /// The first instance to compare.
+ /// The object to compare.
+ /// True if strong and value represent the same decimal; otherwise, false.
+ public static bool operator ==(StrongDecimal? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is decimal decimalValue)
+ {
+ return strong.Value == decimalValue;
+ }
+
+ if (other is StrongDecimal otherStrong)
+ {
+ return strong.Value == otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether two specified instances of StrongDecimal are not equal.
+ ///
+ /// The first instance to compare.
+ /// The object to compare.
+ /// True if strong and other do not represent the same decimal; otherwise, false.
+ public static bool operator !=(StrongDecimal? strong, object? other)
+ {
+ return (strong == other) is false;
+ }
+
+ ///
+ /// Determines whether a object is less than another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is less than the object;
+ /// otherwise, .
+ ///
+ public static bool operator <(StrongDecimal? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is decimal decimalValue)
+ {
+ return strong.Value < decimalValue;
+ }
+
+ if (other is StrongDecimal otherStrong)
+ {
+ return strong.Value < otherStrong.Value;
+ }
+
+ if (other is int intValue)
+ {
+ return strong.Value < intValue;
+ }
+
+ if (other is long longValue)
+ {
+ return strong.Value < longValue;
+ }
+
+ if (other is uint uintValue)
+ {
+ return strong.Value < uintValue;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is greater than another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is greater than the object;
+ /// otherwise, .
+ ///
+ public static bool operator >(StrongDecimal? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is decimal decimalValue)
+ {
+ return strong.Value > decimalValue;
+ }
+
+ if (other is StrongDecimal otherStrong)
+ {
+ return strong.Value > otherStrong.Value;
+ }
+
+ if (other is int intValue)
+ {
+ return strong.Value > intValue;
+ }
+
+ if (other is long longValue)
+ {
+ return strong.Value > longValue;
+ }
+
+ if (other is uint uintValue)
+ {
+ return strong.Value > uintValue;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is less than or equal to another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is less than or equal to the object;
+ /// otherwise, .
+ ///
+ public static bool operator <=(StrongDecimal? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is decimal decimalValue)
+ {
+ return strong.Value <= decimalValue;
+ }
+
+ if (other is StrongDecimal otherStrong)
+ {
+ return strong.Value <= otherStrong.Value;
+ }
+
+ if (other is int intValue)
+ {
+ return strong.Value <= intValue;
+ }
+
+ if (other is long longValue)
+ {
+ return strong.Value <= longValue;
+ }
+
+ if (other is uint uintValue)
+ {
+ return strong.Value <= uintValue;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is greater than or equal to another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is greater than or equal to the object;
+ /// otherwise, .
+ ///
+ public static bool operator >=(StrongDecimal? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is decimal decimalValue)
+ {
+ return strong.Value >= decimalValue;
+ }
+
+ if (other is StrongDecimal otherStrong)
+ {
+ return strong.Value >= otherStrong.Value;
+ }
+
+ if (other is int intValue)
+ {
+ return strong.Value >= intValue;
+ }
+
+ if (other is long longValue)
+ {
+ return strong.Value >= longValue;
+ }
+
+ if (other is uint uintValue)
+ {
+ return strong.Value >= uintValue;
+ }
+
+ return false;
+ }
+}
diff --git a/src/StrongOf/StrongDecimal.cs b/src/StrongOf/StrongDecimal.cs
index e6cd707..06d2f1e 100644
--- a/src/StrongOf/StrongDecimal.cs
+++ b/src/StrongOf/StrongDecimal.cs
@@ -7,7 +7,8 @@ namespace StrongOf;
/// Represents a strongly typed decimal.
///
/// The type of the strong decimal.
-public abstract class StrongDecimal(decimal Value) : StrongOf(Value), IComparable, IStrongDecimal
+public abstract partial class StrongDecimal(decimal Value)
+ : StrongOf(Value), IComparable, IStrongDecimal
where TStrong : StrongDecimal
{
///
@@ -49,18 +50,19 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
- /// Tries to parse a decimal from a ReadOnlySpan of char and returns a value that indicates whether the operation succeeded.
+ /// Tries to parse the specified content into a object.
///
- /// A ReadOnlySpan of char containing a decimal to convert.
- /// When this method returns, contains the decimal value equivalent to the decimal contained in content, if the conversion succeeded, or null if the conversion failed.
- /// True if content was converted successfully; otherwise, false.
- public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong)
+ /// The content to parse.
+ /// When this method returns, contains the parsed value if the parsing succeeded, or null if the parsing failed. The parsing is case-sensitive.
+ /// An optional that supplies culture-specific formatting information.
+ /// true if the parsing was successful; otherwise, false.
+ public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong, IFormatProvider? formatProvider = null)
{
- if (decimal.TryParse(content, out decimal value))
+ if (decimal.TryParse(content, formatProvider, out decimal value))
{
strong = From(value);
return true;
@@ -109,45 +111,6 @@ public static bool TryParse(ReadOnlySpan content, NumberStyles numberStyle
return false;
}
- // Operators
-
- ///
- /// Determines whether two specified instances of StrongDecimal are equal.
- ///
- /// The first instance to compare.
- /// The object to compare.
- /// True if strong and value represent the same decimal; otherwise, false.
- public static bool operator ==(StrongDecimal? strong, object? other)
- {
- if (strong is null)
- {
- return other is null;
- }
-
- if (other is decimal decimalValue)
- {
- return strong.Value == decimalValue;
- }
-
- if (other is StrongDecimal otherStrong)
- {
- return strong.Value == otherStrong.Value;
- }
-
- return false;
- }
-
- ///
- /// Determines whether two specified instances of StrongDecimal are not equal.
- ///
- /// The first instance to compare.
- /// The object to compare.
- /// True if strong and other do not represent the same decimal; otherwise, false.
- public static bool operator !=(StrongDecimal? strong, object? other)
- {
- return (strong == other) is false;
- }
-
// Equals
///
diff --git a/src/StrongOf/StrongGuid.Operators.cs b/src/StrongOf/StrongGuid.Operators.cs
new file mode 100644
index 0000000..f9af57b
--- /dev/null
+++ b/src/StrongOf/StrongGuid.Operators.cs
@@ -0,0 +1,180 @@
+namespace StrongOf;
+
+public abstract partial class StrongGuid
+{
+ ///
+ /// Determines whether two specified instances of StrongGuid are equal.
+ ///
+ /// The first instance to compare.
+ /// The object to compare.
+ /// True if strong and value represent the same Guid; otherwise, false.
+ public static bool operator ==(StrongGuid? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is Guid guidValue)
+ {
+ return strong.Value == guidValue;
+ }
+
+ if (other is StrongGuid otherStrong)
+ {
+ return strong.Value == otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether two specified instances of StrongGuid are not equal.
+ ///
+ /// The first instance to compare.
+ /// The object to compare.
+ /// True if strong and other do not represent the same Guid; otherwise, false.
+ public static bool operator !=(StrongGuid? strong, object? other)
+ {
+ return (strong == other) is false;
+ }
+
+ ///
+ /// Determines whether a object is greater than another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is greater than the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a , the method compares the value of with the value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+ public static bool operator >(StrongGuid? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is Guid guidValue)
+ {
+ return strong.Value > guidValue;
+ }
+
+ if (other is StrongGuid otherStrong)
+ {
+ return strong.Value > otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is less than another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is less than the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a , the method compares the value of with the value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+
+ public static bool operator <(StrongGuid? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is Guid guidValue)
+ {
+ return strong.Value < guidValue;
+ }
+
+ if (other is StrongGuid otherStrong)
+ {
+ return strong.Value < otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is greater than or equal to another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is greater than or equal to the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a , the method compares the value of with the value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+
+ public static bool operator >=(StrongGuid? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is Guid guidValue)
+ {
+ return strong.Value >= guidValue;
+ }
+
+ if (other is StrongGuid otherStrong)
+ {
+ return strong.Value >= otherStrong.Value;
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether a object is less than or equal to another object.
+ ///
+ /// The object to compare.
+ /// The object to compare with the object.
+ ///
+ /// if the object is less than or equal to the object;
+ /// otherwise, .
+ ///
+ ///
+ /// If is , the method returns if is also , otherwise .
+ /// If is a , the method compares the value of with the value.
+ /// If is a object, the method compares the value of with the value of the other object.
+ ///
+
+ public static bool operator <=(StrongGuid? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is Guid guidValue)
+ {
+ return strong.Value <= guidValue;
+ }
+
+ if (other is StrongGuid otherStrong)
+ {
+ return strong.Value <= otherStrong.Value;
+ }
+
+ return false;
+ }
+}
diff --git a/src/StrongOf/StrongGuid.cs b/src/StrongOf/StrongGuid.cs
index 4f2e67f..a153d97 100644
--- a/src/StrongOf/StrongGuid.cs
+++ b/src/StrongOf/StrongGuid.cs
@@ -6,7 +6,8 @@ namespace StrongOf;
/// Represents a strong type of Guid.
///
/// The type of the strong Guid.
-public abstract class StrongGuid(Guid Value) : StrongOf(Value), IComparable, IStrongGuid
+public abstract partial class StrongGuid(Guid Value)
+ : StrongOf(Value), IComparable, IStrongGuid
where TStrong : StrongGuid
{
///
@@ -72,7 +73,7 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
@@ -136,46 +137,6 @@ public string ToStringWithDashes()
public string ToStringWithoutDashes()
=> Value.ToString("N");
- // Operators
-
- ///
- /// Determines whether two specified instances of StrongGuid are equal.
- ///
- /// The first instance to compare.
- /// The object to compare.
- /// True if strong and value represent the same Guid; otherwise, false.
- public static bool operator ==(StrongGuid? strong, object? other)
- {
- if (strong is null)
- {
- return other is null;
- }
-
- if (other is Guid guidValue)
- {
- return strong.Value == guidValue;
- }
-
- if (other is StrongGuid otherStrong)
- {
- return strong.Value == otherStrong.Value;
- }
-
- return false;
- }
-
- ///
- /// Determines whether two specified instances of StrongGuid are not equal.
- ///
- /// The first instance to compare.
- /// The object to compare.
- /// True if strong and other do not represent the same Guid; otherwise, false.
- public static bool operator !=(StrongGuid? strong, object? other)
- {
- return (strong == other) is false;
- }
-
-
// Equals
///
diff --git a/src/StrongOf/StrongInt32.cs b/src/StrongOf/StrongInt32.cs
index 30925ea..ed85f63 100644
--- a/src/StrongOf/StrongInt32.cs
+++ b/src/StrongOf/StrongInt32.cs
@@ -6,7 +6,8 @@ namespace StrongOf;
/// Represents a strong type of Int32.
///
/// The type of the strong Int32.
-public abstract partial class StrongInt32(int Value) : StrongOf(Value), IComparable, IStrongInt32
+public abstract partial class StrongInt32(int Value)
+ : StrongOf(Value), IComparable, IStrongInt32
where TStrong : StrongInt32
{
///
@@ -53,18 +54,19 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
- /// Tries to parse an Int32 from a ReadOnlySpan of char and returns a value that indicates whether the operation succeeded.
+ /// Tries to parse the specified content into a object.
///
- /// A ReadOnlySpan of char containing an Int32 to convert.
- /// When this method returns, contains the Int32 value equivalent to the Int32 contained in content, if the conversion succeeded, or null if the conversion failed.
- /// True if content was converted successfully; otherwise, false.
- public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong)
+ /// The content to parse.
+ /// When this method returns, contains the parsed value if the parsing succeeded, or null if the parsing failed. The parsing is case-sensitive.
+ /// An optional that supplies culture-specific formatting information.
+ /// true if the parsing was successful; otherwise, false.
+ public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong, IFormatProvider? formatProvider = null)
{
- if (int.TryParse(content, out int value))
+ if (int.TryParse(content, formatProvider, out int value))
{
strong = From(value);
return true;
diff --git a/src/StrongOf/StrongInt64.cs b/src/StrongOf/StrongInt64.cs
index f441af7..126ac87 100644
--- a/src/StrongOf/StrongInt64.cs
+++ b/src/StrongOf/StrongInt64.cs
@@ -6,7 +6,8 @@ namespace StrongOf;
/// Represents a strong type of Int64.
///
/// The type of the strong Int64.
-public abstract partial class StrongInt64(long Value) : StrongOf(Value), IComparable, IStrongInt64
+public abstract partial class StrongInt64(long Value)
+ : StrongOf(Value), IComparable, IStrongInt64
where TStrong : StrongInt64
{
@@ -54,18 +55,19 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
- /// Tries to parse an Int64 from a ReadOnlySpan of char and returns a value that indicates whether the operation succeeded.
+ /// Tries to parse the specified content into a object.
///
- /// A ReadOnlySpan of char containing an Int64 to convert.
- /// When this method returns, contains the Int64 value equivalent to the Int64 contained in content, if the conversion succeeded, or null if the conversion failed.
- /// True if content was converted successfully; otherwise, false.
- public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong)
+ /// The content to parse.
+ /// When this method returns, contains the parsed value if the parsing succeeded, or null if the parsing failed. The parsing is case-sensitive.
+ /// An optional that supplies culture-specific formatting information.
+ /// true if the parsing was successful; otherwise, false.
+ public static bool TryParse(ReadOnlySpan content, [NotNullWhen(true)] out TStrong? strong, IFormatProvider? formatProvider = null)
{
- if (long.TryParse(content, out long value))
+ if (long.TryParse(content, formatProvider, out long value))
{
strong = From(value);
return true;
diff --git a/src/StrongOf/StrongOf.cs b/src/StrongOf/StrongOf.cs
index 7409cd3..55d2df7 100644
--- a/src/StrongOf/StrongOf.cs
+++ b/src/StrongOf/StrongOf.cs
@@ -3,12 +3,15 @@
namespace StrongOf;
+#pragma warning disable MA0049 // Type name should not match containing namespace
+
///
/// Represents a strong type of TTarget.
///
/// The type of the target.
/// The type of the strong.
-public abstract class StrongOf : IStrongOf
+public abstract class StrongOf
+ : IStrongOf, IEquatable>
where TStrong : StrongOf
{
private static readonly Func s_factoryWithParameter;
@@ -51,7 +54,7 @@ public static TStrong From(TTarget value)
/// The source to create the list of strong types from.
/// A list of strong types.
[return: NotNullIfNotNull(nameof(source))]
- public static List? From(IEnumerable? source)
+ public static ICollection? From(IEnumerable? source)
=> source?.Select(e => From(e)).ToList();
@@ -132,8 +135,13 @@ public override bool Equals(object? other)
///
/// The StrongOf to compare with the current StrongOf.
/// True if the specified StrongOf is equal to the current StrongOf; otherwise, false.
- public virtual bool Equals(StrongOf other)
+ public virtual bool Equals(StrongOf? other)
{
+ if (other is null)
+ {
+ return false;
+ }
+
return s_comparer.Equals(Value, other.Value);
}
diff --git a/src/StrongOf/StrongOf.csproj b/src/StrongOf/StrongOf.csproj
index f13cfe7..be03d13 100644
--- a/src/StrongOf/StrongOf.csproj
+++ b/src/StrongOf/StrongOf.csproj
@@ -1,5 +1,12 @@
+
+
+ all
+ runtime; build; native; contentfiles; analyzers
+
+
+
true
readme.md
@@ -7,8 +14,8 @@
-
-
+
+
diff --git a/src/StrongOf/StrongString.Methods.cs b/src/StrongOf/StrongString.Methods.cs
index 8b90930..fc8d524 100644
--- a/src/StrongOf/StrongString.Methods.cs
+++ b/src/StrongOf/StrongString.Methods.cs
@@ -1,7 +1,9 @@
using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
namespace StrongOf;
+#pragma warning disable MA0097 // A class that implements IComparable or IComparable should override comparison operators
public abstract partial class StrongString
{
///
@@ -47,8 +49,8 @@ public bool Equals(T other, StringComparison stringComparison) where T : TStr
/// Returns a copy of this string converted to lowercase.
///
/// A string in lowercase.
- public TStrong ToLower()
- => From(Value.ToLower());
+ public TStrong ToLower(CultureInfo? cultureInfo = null)
+ => From(Value.ToLower(cultureInfo));
///
/// Returns a copy of this string converted to lowercase, using the casing rules of the invariant culture.
@@ -61,8 +63,8 @@ public TStrong ToLowerInvariant()
/// Returns a copy of this string converted to uppercase.
///
/// A string in uppercase.
- public TStrong ToUpper()
- => From(Value.ToUpper());
+ public TStrong ToUpper(CultureInfo? cultureInfo = null)
+ => From(Value.ToUpper(cultureInfo));
///
/// Returns a copy of this string converted to uppercase, using the casing rules of the invariant culture.
@@ -91,7 +93,7 @@ public char FirstCharUpperInvariant()
/// A set of characters that are allowed in the string.
/// When this method returns, contains the collection of invalid characters, if any. This parameter is passed uninitialized.
/// true if the current string contains any characters not present in the allowedChars parameter; otherwise, false.
- public bool ContainsInvalidChars(HashSet allowedChars, [NotNullWhen(true)] out ICollection? invalidCharacters)
+ public bool ContainsInvalidChars(ICollection allowedChars, [NotNullWhen(true)] out ICollection? invalidCharacters)
{
HashSet? invalidChars = null;
diff --git a/src/StrongOf/StrongString.Operators.cs b/src/StrongOf/StrongString.Operators.cs
new file mode 100644
index 0000000..430af09
--- /dev/null
+++ b/src/StrongOf/StrongString.Operators.cs
@@ -0,0 +1,43 @@
+namespace StrongOf;
+
+#pragma warning disable MA0097 // A class that implements IComparable or IComparable should override comparison operators
+
+public abstract partial class StrongString
+{
+ ///
+ /// Determines whether the specified strong string and string are equal.
+ ///
+ /// The strong string to compare.
+ /// The object to compare.
+ /// True if the specified strong string and string are equal; otherwise, false.
+ public static bool operator ==(StrongString? strong, object? other)
+ {
+ if (strong is null)
+ {
+ return other is null;
+ }
+
+ if (other is string stringValue)
+ {
+ return strong.Value.Equals(stringValue, StringComparison.Ordinal);
+ }
+
+ if (other is StrongString otherStrong)
+ {
+ return string.Equals(strong.Value, otherStrong.Value, StringComparison.Ordinal);
+ }
+
+ return false;
+ }
+
+ ///
+ /// Determines whether the specified strong string and string are not equal.
+ ///
+ /// The strong string to compare.
+ /// The object to compare.
+ /// True if the specified strong string and string are not equal; otherwise, false.
+ public static bool operator !=(StrongString? strong, object? other)
+ {
+ return (strong == other) is false;
+ }
+}
diff --git a/src/StrongOf/StrongString.Properties.cs b/src/StrongOf/StrongString.Properties.cs
index 7472064..732d805 100644
--- a/src/StrongOf/StrongString.Properties.cs
+++ b/src/StrongOf/StrongString.Properties.cs
@@ -1,5 +1,7 @@
namespace StrongOf;
+#pragma warning disable MA0097 // A class that implements IComparable or IComparable should override comparison operators
+
public abstract partial class StrongString
{
///
diff --git a/src/StrongOf/StrongString.cs b/src/StrongOf/StrongString.cs
index d8156be..3df3617 100644
--- a/src/StrongOf/StrongString.cs
+++ b/src/StrongOf/StrongString.cs
@@ -2,11 +2,14 @@
namespace StrongOf;
+#pragma warning disable MA0097 // A class that implements IComparable or IComparable should override comparison operators
+
///
/// Represents a strong type of string.
///
/// The type of the strong string.
-public abstract partial class StrongString(string Value) : StrongOf(Value), IComparable, IStrongString
+public abstract partial class StrongString(string Value)
+ : StrongOf(Value), IComparable, IStrongString
where TStrong : StrongString
{
///
@@ -56,7 +59,7 @@ public int CompareTo(object? other)
return Value.CompareTo(otherStrong.Value);
}
- throw new ArgumentException($"Object is not a {typeof(TStrong)}");
+ throw new ArgumentException($"Object is not a {typeof(TStrong)}", nameof(other));
}
///
@@ -73,45 +76,6 @@ public static TStrong Empty()
public bool IsEmpty()
=> Value == "";
- // Operators
-
- ///
- /// Determines whether the specified strong string and string are equal.
- ///
- /// The strong string to compare.
- /// The object to compare.
- /// True if the specified strong string and string are equal; otherwise, false.
- public static bool operator ==(StrongString? strong, object? other)
- {
- if (strong is null)
- {
- return other is null;
- }
-
- if (other is string stringValue)
- {
- return strong.Value == stringValue;
- }
-
- if (other is StrongString otherStrong)
- {
- return strong.Value == otherStrong.Value;
- }
-
- return false;
- }
-
- ///
- /// Determines whether the specified strong string and string are not equal.
- ///
- /// The strong string to compare.
- /// The object to compare.
- /// True if the specified strong string and string are not equal; otherwise, false.
- public static bool operator !=(StrongString? strong, object? other)
- {
- return (strong == other) is false;
- }
-
// Equals
///
diff --git a/tests/StrongOf.Json.UnitTests/StrongDateTimeJsonConverterTests.cs b/tests/StrongOf.Json.UnitTests/StrongDateTimeJsonConverterTests.cs
index 8379dea..fa25c40 100644
--- a/tests/StrongOf.Json.UnitTests/StrongDateTimeJsonConverterTests.cs
+++ b/tests/StrongOf.Json.UnitTests/StrongDateTimeJsonConverterTests.cs
@@ -25,7 +25,7 @@ public void Read_ValidJson_ReturnsStrongDateTime()
// Act
TestDateTimeOffsetOf? result = _converter.Read(ref reader, typeof(TestDateTimeOffsetOf), _options);
- DateTime expected = DateTime.ParseExact("2023-12-17T14:24:22.6412808+00:00", "o", CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AdjustToUniversal);
+ DateTime expected = DateTime.ParseExact("2023-12-17T14:24:22.6412808+00:00", "o", CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.None);
// Assert
Assert.NotNull(result);
diff --git a/tests/StrongOf.UnitTests/StrongChar_As_Tests.cs b/tests/StrongOf.UnitTests/StrongChar_As_Tests.cs
index c3427dc..4e92ab7 100644
--- a/tests/StrongOf.UnitTests/StrongChar_As_Tests.cs
+++ b/tests/StrongOf.UnitTests/StrongChar_As_Tests.cs
@@ -15,4 +15,84 @@ public void AsChar_ReturnsCorrectResult()
// Assert
Assert.Equal(strong.Value, strong.AsChar());
}
+
+
+ [Fact]
+ public void FromNullable_WithValue_ReturnsNonNull()
+ {
+ // Arrange
+ char value = 'A';
+
+ // Act
+ TestCharOf result = TestCharOf.FromNullable(value);
+
+ // Assert
+ Assert.NotNull(result);
+ }
+
+ [Fact]
+ public void FromNullable_WithNull_ReturnsNull()
+ {
+ // Arrange
+ char? value = null;
+
+ // Act
+ TestCharOf? result = TestCharOf.FromNullable(value);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public void FromNullable_WithNotNull_ReturnsCorrectValue()
+ {
+ // Arrange
+ char value = 'A';
+
+ // Act
+ TestCharOf result = TestCharOf.FromNullable(value);
+
+ // Assert
+ Assert.Equal(value, result.Value);
+ }
+
+ [Fact]
+ public void CompareTo_WithSameType_ReturnsCorrectComparison()
+ {
+ // Arrange
+ TestCharOf instance1 = new('A');
+ TestCharOf instance2 = new('A');
+
+ // Act
+ int result = instance1.CompareTo(instance2);
+
+ // Assert
+ Assert.Equal(0, result);
+ }
+
+ [Fact]
+ public void CompareTo_WithDifferentType_ThrowsArgumentException()
+ {
+ // Arrange
+ TestCharOf instance = new('A');
+ object other = new ();
+
+ // Act & Assert
+ Assert.Throws(() => instance.CompareTo(other));
+ }
+
+ [Fact]
+ public void GetHashCode_ReturnsConsistentHashCodeForEqualObjects()
+ {
+ // Arrange
+ TestCharOf instance1 = new('A');
+ TestCharOf instance2 = new('A');
+
+ // Act
+ int hashCode1 = instance1.GetHashCode();
+ int hashCode2 = instance2.GetHashCode();
+
+ // Assert
+ Assert.Equal(hashCode1, hashCode2);
+ }
}
diff --git a/tests/StrongOf.UnitTests/StrongChar_Operators_Tests.cs b/tests/StrongOf.UnitTests/StrongChar_Operators_Tests.cs
new file mode 100644
index 0000000..a3c2106
--- /dev/null
+++ b/tests/StrongOf.UnitTests/StrongChar_Operators_Tests.cs
@@ -0,0 +1,272 @@
+using Xunit;
+
+namespace StrongOf.UnitTests;
+
+public class StrongChar_Operators_Tests
+{
+ private sealed class TestCharOf(char Value) : StrongChar(Value) { }
+
+ [Fact]
+ public void EqualityOperator_WithNullStrongAndNullObject_ReturnsTrue()
+ {
+ // Arrange & Act
+ bool result = (TestCharOf?)null == null;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void EqualityOperator_WithNonNullStrongAndNullObject_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf strong = new('A');
+
+ // Act
+ bool result = strong == null;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void EqualityOperator_WithCharAndStrongChar_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestCharOf strong = new('A');
+ char charValue = 'A';
+ char differentCharValue = 'B';
+
+ // Act
+ bool result1 = strong == charValue;
+ bool result2 = strong == new TestCharOf(differentCharValue);
+
+ // Assert
+ Assert.True(result1);
+ Assert.False(result2);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithNonNullStrongCharAndNonNullOtherChar_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestCharOf strong = new('a');
+ object other = 'b';
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithNullStrongChar_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object? other = 'b';
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithNonNullStrongCharAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf strong = new('a');
+ object? other = null;
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithNonNullStrongCharAndNonNullOtherChar_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestCharOf strong = new('b');
+ object other = 'a';
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithNullStrongChar_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object other = 'b';
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithNonNullStrongCharAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf strong = new('b');
+ object? other = null;
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithNonNullStrongCharAndNonNullOtherChar_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestCharOf strong = new('a');
+ object other = 'b';
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithNullStrongChar_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object other = 'b';
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithNonNullStrongCharAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf strong = new('a');
+ object? other = null;
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithNonNullStrongCharAndNonNullOtherChar_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestCharOf? strong = new('b');
+ object other = 'a';
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithNullStrongChar_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object other = 'b';
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithNonNullStrongCharAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestCharOf strong = new('b');
+ object? other = null;
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestCharOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.True(result);
+ }
+}
diff --git a/tests/StrongOf.UnitTests/StrongDateTime_As_Tests.cs b/tests/StrongOf.UnitTests/StrongDateTime_As_Tests.cs
index fd72cef..7cafb73 100644
--- a/tests/StrongOf.UnitTests/StrongDateTime_As_Tests.cs
+++ b/tests/StrongOf.UnitTests/StrongDateTime_As_Tests.cs
@@ -1,4 +1,5 @@
-using Xunit;
+using System.Globalization;
+using Xunit;
namespace StrongOf.Tests;
@@ -6,6 +7,45 @@ public class StrongDateTime_As_Tests
{
private sealed class TestDateTimeOf(DateTime Value) : StrongDateTime(Value) { }
+ [Fact]
+ public void FromNullable_WithValue_ReturnsNonNull()
+ {
+ // Arrange
+ DateTime value = DateTime.UtcNow;
+
+ // Act
+ TestDateTimeOf result = TestDateTimeOf.FromNullable(value);
+
+ // Assert
+ Assert.NotNull(result);
+ }
+
+ [Fact]
+ public void FromNullable_WithNull_ReturnsNull()
+ {
+ // Arrange
+ DateTime? value = null;
+
+ // Act
+ TestDateTimeOf? result = TestDateTimeOf.FromNullable(value);
+
+ // Assert
+ Assert.Null(result);
+ }
+
+ [Fact]
+ public void FromNullable_WithNotNull_ReturnsCorrectValue()
+ {
+ // Arrange
+ DateTime value = DateTime.UtcNow;
+
+ // Act
+ TestDateTimeOf result = TestDateTimeOf.FromNullable(value);
+
+ // Assert
+ Assert.Equal(value, result.Value);
+ }
+
[Fact]
public void AsDateTime_ReturnsCorrectResult()
{
@@ -45,4 +85,66 @@ public void AsTime_ReturnsCorrectResult()
// Assert
Assert.Equal(TimeOnly.FromDateTime(strong.Value), strong.AsTime());
}
+
+ [Fact]
+ public void TryParseIso8601_WithValidInput_ReturnsTrueAndNonNull()
+ {
+ // Arrange
+ ReadOnlySpan content = "2022-01-02T00:00:00+00:00".AsSpan();
+ TestDateTimeOf? expected = TestDateTimeOf.From(DateTime.Parse("2022-01-02T00:00:00+00:00"));
+
+ // Act
+ bool result = TestDateTimeOf.TryParseIso8601(content, out TestDateTimeOf? strong);
+
+ // Assert
+ Assert.True(result);
+ Assert.NotNull(strong);
+ Assert.Equal(expected, strong);
+ }
+
+ [Fact]
+ public void TryParseIso8601_WithInvalidInput_ReturnsFalseAndNull()
+ {
+ // Arrange
+ ReadOnlySpan content = "invalid-date".AsSpan();
+
+ // Act
+ bool result = TestDateTimeOf.TryParseIso8601(content, out TestDateTimeOf? strong);
+
+ // Assert
+ Assert.False(result);
+ Assert.Null(strong);
+ }
+
+ [Fact]
+ public void TryParseExact_WithValidInput_ReturnsTrueAndNonNull()
+ {
+ // Arrange
+ ReadOnlySpan content = "2024-04-26T12:00:00".AsSpan();
+ string format = "yyyy-MM-ddTHH:mm:ss";
+ TestDateTimeOf? expected = TestDateTimeOf.From(DateTime.ParseExact("2024-04-26T12:00:00", format, CultureInfo.InvariantCulture));
+
+ // Act
+ bool result = TestDateTimeOf.TryParseExact(content, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out TestDateTimeOf? strong);
+
+ // Assert
+ Assert.True(result);
+ Assert.NotNull(strong);
+ Assert.Equal(expected, strong);
+ }
+
+ [Fact]
+ public void TryParseExact_WithInvalidInput_ReturnsFalseAndNull()
+ {
+ // Arrange
+ ReadOnlySpan content = "invalid-date".AsSpan();
+ string format = "yyyy-MM-ddTHH:mm:ss";
+
+ // Act
+ bool result = TestDateTimeOf.TryParseExact(content, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out TestDateTimeOf? strong);
+
+ // Assert
+ Assert.False(result);
+ Assert.Null(strong);
+ }
}
diff --git a/tests/StrongOf.UnitTests/StrongDateTime_Tests.cs b/tests/StrongOf.UnitTests/StrongDateTime_Tests.cs
index 24a69ee..9525436 100644
--- a/tests/StrongOf.UnitTests/StrongDateTime_Tests.cs
+++ b/tests/StrongOf.UnitTests/StrongDateTime_Tests.cs
@@ -42,6 +42,34 @@ public void TryParse_ShouldReturnFalseForInvalidDateTime()
Assert.Null(strong);
}
+ [Fact]
+ public void ToString_DelegatesCallToUnderlyingValue_WithDefaultProvider()
+ {
+ // Arrange
+ TestDateTimeOf strong = new(new DateTime(2000, 1, 1));
+ string expected = strong.Value.ToString();
+
+ // Act
+ string result = strong.ToString();
+
+ // Assert
+ Assert.Equal(expected, result);
+ }
+
+ [Fact]
+ public void ToString_DelegatesCallToUnderlyingValue_WithCustomProvider()
+ {
+ // Arrange
+ TestDateTimeOf strong = new(new DateTime(2000, 1, 1));
+ string expected = strong.Value.ToString("o", CultureInfo.InvariantCulture);
+
+ // Act
+ string result = strong.ToString("o", CultureInfo.InvariantCulture);
+
+ // Assert
+ Assert.Equal(expected, result);
+ }
+
[Fact]
public void ToString_Iso8601()
{
diff --git a/tests/StrongOf.UnitTests/StrongDecimal_Operators_Tests.cs b/tests/StrongOf.UnitTests/StrongDecimal_Operators_Tests.cs
new file mode 100644
index 0000000..99b35c5
--- /dev/null
+++ b/tests/StrongOf.UnitTests/StrongDecimal_Operators_Tests.cs
@@ -0,0 +1,231 @@
+using Xunit;
+
+namespace StrongOf.UnitTests;
+
+public class StrongDecimal_Operators_Tests
+{
+ private sealed class TestDecimalOf(decimal Value) : StrongDecimal(Value) { }
+
+ [Fact]
+ public void LessThanOperator_WithNonNullStrongDecimalAndNonNullDecimalOther_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestDecimalOf strong = new(10.5m);
+ object other = 15.7m;
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithNullStrongDecimal_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object other = 15.7m;
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithNonNullStrongDecimalAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf strong = new(10.5m);
+ object? other = null;
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong < other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithNonNullStrongDecimalAndNonNullDecimalOther_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestDecimalOf strong = new(15.7m);
+ object other = 10.5m;
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithNullStrongDecimal_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object other = 15.7m;
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithNonNullStrongDecimalAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf strong = new(15.7m);
+ object? other = null;
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong > other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithNonNullStrongDecimalAndNonNullDecimalOther_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestDecimalOf strong = new(10.5m);
+ object other = 15.7m;
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithNullStrongDecimal_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object other = 15.7m;
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithNonNullStrongDecimalAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf strong = new(10.5m);
+ object? other = null;
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void LessThanOrEqualOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong <= other;
+
+ // Assert
+ Assert.True(result);
+ }
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithNonNullStrongDecimalAndNonNullDecimalOther_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestDecimalOf strong = new(15.7m);
+ object other = 10.5m;
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithNullStrongDecimal_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object other = 15.7m;
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithNonNullStrongDecimalAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestDecimalOf strong = new(15.7m);
+ object? other = null;
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void GreaterThanOrEqualOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestDecimalOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong >= other;
+
+ // Assert
+ Assert.True(result);
+ }
+}
diff --git a/tests/StrongOf.UnitTests/StrongString_Operators_Tests.cs b/tests/StrongOf.UnitTests/StrongString_Operators_Tests.cs
new file mode 100644
index 0000000..ccce6b3
--- /dev/null
+++ b/tests/StrongOf.UnitTests/StrongString_Operators_Tests.cs
@@ -0,0 +1,78 @@
+using Xunit;
+
+namespace StrongOf.UnitTests;
+
+public class StrongString_Operators_Tests
+{
+ private sealed class TestStringOf(string Value) : StrongString(Value) { }
+
+ [Fact]
+ public void EqualityOperator_WithNonNullStrongStringAndNonNullStringOther_ReturnsCorrectResult()
+ {
+ // Arrange
+ TestStringOf strong = new("hello");
+ object other = "hello";
+
+ // Act
+ bool result = strong == other;
+
+ // Assert
+ Assert.True(result);
+ }
+
+ [Fact]
+ public void EqualityOperator_WithNonNullStrongStringAndNonNullStringOther_ReturnsIncorrectResult()
+ {
+ // Arrange
+ TestStringOf strong = new("hello");
+ object other = "world";
+
+ // Act
+ bool result = strong == other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void EqualityOperator_WithNullStrongStringAndNonNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestStringOf? strong = null;
+ object other = "world";
+
+ // Act
+ bool result = strong == other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void EqualityOperator_WithNonNullStrongStringAndNullOther_ReturnsFalse()
+ {
+ // Arrange
+ TestStringOf strong = new("hello");
+ object? other = null;
+
+ // Act
+ bool result = strong == other;
+
+ // Assert
+ Assert.False(result);
+ }
+
+ [Fact]
+ public void EqualityOperator_WithBothNull_ReturnsTrue()
+ {
+ // Arrange
+ TestStringOf? strong = null;
+ object? other = null;
+
+ // Act
+ bool result = strong == other;
+
+ // Assert
+ Assert.True(result);
+ }
+}