Skip to content

Add ParseOrNull to major value types#9

Merged
Tyrrrz merged 5 commits intoprimefrom
copilot/add-parse-or-null-to-major-value-types
Apr 12, 2026
Merged

Add ParseOrNull to major value types#9
Tyrrrz merged 5 commits intoprimefrom
copilot/add-parse-or-null-to-major-value-types

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 12, 2026

Adds ParseOrNull as a static extension method on major value types, mirroring the pattern from GitHubActionsTestLogger. Each method takes a string? and returns a nullable of the target type, yielding null on failure.

Types covered

Type Simple overload defaults Full overload parameters
int, long NumberStyles.Integer, CurrentCulture NumberStyles, IFormatProvider?
double NumberStyles.Float | AllowThousands, CurrentCulture NumberStyles, IFormatProvider?
decimal NumberStyles.Number, CurrentCulture NumberStyles, IFormatProvider?
bool bool.TryParse
DateTime, DateTimeOffset CurrentCulture, DateTimeStyles.None IFormatProvider?, DateTimeStyles
TimeSpan CurrentCulture IFormatProvider?
Guid Guid.TryParse

Each type (except bool and Guid, which have no BCL formatting parameters) exposes a full overload accepting explicit formatting options. The simple ParseOrNull(string?) overload delegates to the full overload using CultureInfo.CurrentCulture as the default, consistent with the behavior of the base Parse methods.

Usage

// Simple overload (uses current culture, like Parse)
int.ParseOrNull("42")       // 42
int.ParseOrNull("abc")      // null
int.ParseOrNull(null)       // null

// Full overload with custom formatting
int.ParseOrNull("FF", NumberStyles.HexNumber, CultureInfo.InvariantCulture)  // 255

bool.ParseOrNull("true")    // true
Guid.ParseOrNull("not-a-guid") // null

Structure

Each type has its own dedicated file and host class (e.g. IntExtensions.cs / IntExtensions, LongExtensions.cs / LongExtensions, etc.), required because static ParseOrNull overloads with the same signature would collide in a single host class under the current C# preview extension member semantics. Tests are organized into matching per-type files (e.g. IntExtensionsTests.cs, LongExtensionsTests.cs, etc.).

Agent-Logs-Url: https://github.com/Tyrrrz/PowerKit/sessions/4dc30744-0f1d-4c83-af52-2231f02919ee

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Split each extension block into its own class/file.
  2. Add overloads that allow passing custom formatting options, etc. Make the current overloads call those.
  3. Test only the outermost overloads.

@copilot

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 8583988:

  1. ParsingExtensions.cs is deleted — each type now has its own file (IntParsingExtensions.cs, LongParsingExtensions.cs, DoubleParsingExtensions.cs, DecimalParsingExtensions.cs, BoolParsingExtensions.cs, DateTimeParsingExtensions.cs, DateTimeOffsetParsingExtensions.cs, TimeSpanParsingExtensions.cs, GuidParsingExtensions.cs).
  2. Formatting-options overloads added where applicable — numeric types get (string?, NumberStyles, IFormatProvider?), date/time types get (string?, IFormatProvider?, DateTimeStyles), TimeSpan gets (string?, IFormatProvider?). The simple overloads delegate to these. bool and Guid have no standard formatting parameters so they stay single-overload.
  3. Tests only exercise the outermost ParseOrNull(string?) overloads (unchanged).

Copilot AI requested a review from Tyrrrz April 12, 2026 15:34
@Tyrrrz
Copy link
Copy Markdown
Owner

Tyrrrz commented Apr 12, 2026

Instead of IntParsingExtensions, call it just IntExtensions, etc. Reorganize tests accordingly. @copilot

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 12, 2026

Instead of IntParsingExtensions, call it just IntExtensions, etc. Reorganize tests accordingly. @copilot

Done in 2d70ecf. All 9 host classes renamed (IntParsingExtensionsIntExtensions, etc.) with matching file renames. ParsingExtensionsTests.cs is split into 9 per-type test files (IntExtensionsTests.cs, LongExtensionsTests.cs, etc.), each with a single ParseOrNull_Test method.

@Tyrrrz Tyrrrz marked this pull request as ready for review April 12, 2026 15:41
Copilot AI review requested due to automatic review settings April 12, 2026 15:41
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds ParseOrNull static extension members for common value types in PowerKit.Extensions, providing a nullable-returning parse helper that defaults to InvariantCulture (where applicable) and returns null on unsuccessful parsing.

Changes:

  • Introduces ParseOrNull(string?) + (where applicable) formatting-parameter overloads for int, long, double, decimal, DateTime, DateTimeOffset, TimeSpan, plus simple bool and Guid variants.
  • Adds per-type unit tests validating basic success/failure/null cases for the simple overloads.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
PowerKit/Extensions/BoolExtensions.cs Adds bool.ParseOrNull(string?) wrapper over bool.TryParse.
PowerKit/Extensions/GuidExtensions.cs Adds Guid.ParseOrNull(string?) wrapper over Guid.TryParse.
PowerKit/Extensions/IntExtensions.cs Adds int.ParseOrNull (default + NumberStyles/IFormatProvider overload).
PowerKit/Extensions/LongExtensions.cs Adds long.ParseOrNull (default + NumberStyles/IFormatProvider overload).
PowerKit/Extensions/DoubleExtensions.cs Adds double.ParseOrNull (default + NumberStyles/IFormatProvider overload).
PowerKit/Extensions/DecimalExtensions.cs Adds decimal.ParseOrNull (default + NumberStyles/IFormatProvider overload).
PowerKit/Extensions/DateTimeExtensions.cs Adds DateTime.ParseOrNull (default + IFormatProvider/DateTimeStyles overload).
PowerKit/Extensions/DateTimeOffsetExtensions.cs Adds DateTimeOffset.ParseOrNull (default + IFormatProvider/DateTimeStyles overload).
PowerKit/Extensions/TimeSpanExtensions.cs Adds TimeSpan.ParseOrNull (default + IFormatProvider overload).
PowerKit.Tests/BoolExtensionsTests.cs Adds basic tests for bool.ParseOrNull(string?).
PowerKit.Tests/GuidExtensionsTests.cs Adds basic tests for Guid.ParseOrNull(string?).
PowerKit.Tests/IntExtensionsTests.cs Adds basic tests for int.ParseOrNull(string?).
PowerKit.Tests/LongExtensionsTests.cs Adds basic tests for long.ParseOrNull(string?).
PowerKit.Tests/DoubleExtensionsTests.cs Adds basic tests for double.ParseOrNull(string?).
PowerKit.Tests/DecimalExtensionsTests.cs Adds basic tests for decimal.ParseOrNull(string?).
PowerKit.Tests/DateTimeExtensionsTests.cs Adds basic tests for DateTime.ParseOrNull(string?).
PowerKit.Tests/DateTimeOffsetExtensionsTests.cs Adds basic tests for DateTimeOffset.ParseOrNull(string?).
PowerKit.Tests/TimeSpanExtensionsTests.cs Adds basic tests for TimeSpan.ParseOrNull(string?).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +9 to +16
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
int.ParseOrNull("42").Should().Be(42);
int.ParseOrNull("-7").Should().Be(-7);
int.ParseOrNull("abc").Should().BeNull();
int.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only covers the simple ParseOrNull(string?) overload. Since IntExtensions also introduces the overload that accepts NumberStyles and IFormatProvider, please add at least one test that exercises those parameters (e.g., parsing a hex value with NumberStyles.HexNumber and InvariantCulture) to ensure the overload is wired correctly.

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +16
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
long.ParseOrNull("9876543210").Should().Be(9876543210L);
long.ParseOrNull("-1").Should().Be(-1L);
long.ParseOrNull("abc").Should().BeNull();
long.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only validates the simple ParseOrNull(string?) overload. LongExtensions also adds a NumberStyles/IFormatProvider overload, so it should have explicit test coverage (for example, a hex parse or a culture-specific thousands separator) to confirm the parameters are honored.

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +16
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
double.ParseOrNull("3.14").Should().Be(3.14);
double.ParseOrNull("-1.5").Should().Be(-1.5);
double.ParseOrNull("abc").Should().BeNull();
double.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test suite covers only the default ParseOrNull(string?) behavior. DoubleExtensions also introduces the overload that accepts NumberStyles and IFormatProvider, so please add a test that depends on those parameters (e.g., a culture with ',' decimal separator or parsing a thousands-formatted number) to verify the overload works as intended.

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +16
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
decimal.ParseOrNull("3.14").Should().Be(3.14m);
decimal.ParseOrNull("-1.5").Should().Be(-1.5m);
decimal.ParseOrNull("abc").Should().BeNull();
decimal.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These assertions cover only the default ParseOrNull(string?) overload. Since DecimalExtensions adds a NumberStyles/IFormatProvider overload, please add a test that exercises that overload (for example, parsing a value with thousands separators or with a non-invariant culture) to ensure the formatting parameters are applied.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +16
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
DateTime.ParseOrNull("2024-06-15").Should().Be(new DateTime(2024, 6, 15));
DateTime.ParseOrNull("not a date").Should().BeNull();
DateTime.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test covers only the simple ParseOrNull(string?) overload. DateTimeExtensions also adds an overload that accepts IFormatProvider and DateTimeStyles, so please add a test that requires non-default provider/styles (e.g., parsing a culture-specific date string) to validate that overload is correctly implemented.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +18
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
DateTimeOffset.ParseOrNull("2024-06-15T00:00:00+00:00").Should().Be(
new DateTimeOffset(2024, 6, 15, 0, 0, 0, TimeSpan.Zero)
);
DateTimeOffset.ParseOrNull("not a date").Should().BeNull();
DateTimeOffset.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test only exercises the default ParseOrNull(string?) overload. DateTimeOffsetExtensions also adds an overload taking IFormatProvider and DateTimeStyles, so it needs explicit coverage (e.g., a culture-specific offset date/time format or a styles-dependent case) to ensure the overload parameters are actually used.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +16
[Fact]
public void ParseOrNull_Test()
{
// Act & assert
TimeSpan.ParseOrNull("1:30:00").Should().Be(new TimeSpan(1, 30, 0));
TimeSpan.ParseOrNull("not a timespan").Should().BeNull();
TimeSpan.ParseOrNull(null).Should().BeNull();
Copy link

Copilot AI Apr 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test validates only the invariant-culture default ParseOrNull(string?) overload. TimeSpanExtensions also introduces the overload that accepts an IFormatProvider, so please add at least one test that uses a non-invariant culture-dependent format to confirm the formatProvider parameter is respected.

Copilot uses AI. Check for mistakes.
@Tyrrrz
Copy link
Copy Markdown
Owner

Tyrrrz commented Apr 12, 2026

@copilot the overloads without extra parameters should default to the current culture, to be consistent with the bae Parse method

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 12, 2026

@copilot the overloads without extra parameters should default to the current culture, to be consistent with the bae Parse method

Done in 159aeaa. All 7 simple ParseOrNull(string?) overloads (int, long, double, decimal, DateTime, DateTimeOffset, TimeSpan) now pass CultureInfo.CurrentCulture instead of CultureInfo.InvariantCulture, matching the behavior of the base Parse methods.

Copilot AI requested a review from Tyrrrz April 12, 2026 15:55
@Tyrrrz Tyrrrz merged commit 4a4a6f1 into prime Apr 12, 2026
@Tyrrrz Tyrrrz deleted the copilot/add-parse-or-null-to-major-value-types branch April 12, 2026 16:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants