Skip to content

Add IParsable<T> fallback converter for automatic scalar support#135

Closed
fdcastel wants to merge 1 commit into
xoofx:mainfrom
fdcastel:feature/iparsable-fallback-converter
Closed

Add IParsable<T> fallback converter for automatic scalar support#135
fdcastel wants to merge 1 commit into
xoofx:mainfrom
fdcastel:feature/iparsable-fallback-converter

Conversation

@fdcastel
Copy link
Copy Markdown
Contributor

Motivation

Rather than adding individual converters for every BCL type that can be represented as a string (e.g., IPAddress, IPEndPoint, Version), SharpYaml can leverage the IParsable<T> interface (introduced in .NET 7) as a generic fallback for scalar-to-object conversion.

Currently, types like System.Net.IPAddress that appear as YAML scalars require custom converters. This is a common source of friction for configuration-heavy applications.

Solution

A new YamlParsableConverterFactory + YamlParsableConverter<T> pair is added as a fallback in the built-in converter resolution chain, positioned just before the final YamlObjectConverter<T>:

  • Deserialization: If a type implements IParsable<T>, calls T.TryParse(scalarValue, CultureInfo.InvariantCulture, out result)
  • Serialization: Uses IFormattable.ToString(null, CultureInfo.InvariantCulture) when available, falling back to ToString()
  • Priority: Lower than all other built-in converters — types with dedicated converters (int, DateTime, Guid, etc.) continue using their optimized paths
  • Scope: .NET 7+ only (#if NET7_0_OR_GREATER)

Types automatically supported

This immediately enables scalar support for:

  • System.Net.IPAddress (most impactful for config scenarios)
  • Any user-defined IParsable<T> types

Note: IPEndPoint, Version, and Uri do not implement IParsable<T> in current .NET and would need dedicated converters if needed.

Caveats

  • This is reflection-only (not source-generated). Source generation would need compile-time IParsable<T> detection to emit the same pattern.
  • The converter is marked with [UnconditionalSuppressMessage] for trimming/AOT since it's only reachable through the reflection-based converter resolution path.

Tests

10 tests covering:

  • IPAddress roundtrip (IPv4 and IPv6)
  • Model class with IPAddress properties (deserialize + roundtrip)
  • Custom IParsable<T> struct (Temperature) with roundtrip
  • Invalid value throws YamlException
  • Explicit converter takes priority over IParsable
  • Built-in converters (int) take priority over IParsable
  • Nullable IPAddress? properties (with value and null)

Types implementing IParsable<T> (introduced in .NET 7) are now automatically
deserialized from YAML scalars using T.Parse(value, InvariantCulture). For
serialization, IFormattable.ToString(null, InvariantCulture) is used when
available, with a fallback to ToString().

This provides out-of-the-box support for IPAddress and any user-defined
IParsable<T> types without requiring custom converters.

The fallback is lower priority than all other built-in converters, ensuring
that types with dedicated converters (string, int, DateTime, etc.) continue
to use their optimized paths.
@fdcastel fdcastel changed the title Add IParsable&lt;T&gt; fallback converter for automatic scalar support Add IParsable<T> fallback converter for automatic scalar support Mar 29, 2026
@fdcastel fdcastel marked this pull request as draft March 29, 2026 12:21
@fdcastel
Copy link
Copy Markdown
Contributor Author

@xoofx I’m not certain this is the right direction, so I’m sharing it as an RFC. If you can, I would appreciate your guidance.

@xoofx
Copy link
Copy Markdown
Owner

xoofx commented Mar 29, 2026

So, I'm not sure on this one. As you pointed out many BCL types don't support it, so the interest is quite limited.

For serialization, it might require forcing quotes as the string might conflict with YAML syntax.

This is reflection-only (not source-generated). Source generation would need compile-time IParsable detection to emit the same pattern.

In any case, if such feature was introduced, it would need to support source generator and detect this at compile time.

@fdcastel
Copy link
Copy Markdown
Contributor Author

Got it. 👍🏻

I’m still having trouble finding a sensible way to handle my custom converters and source generators, but I’m optimistic I’ll arrive at a good solution.

@fdcastel
Copy link
Copy Markdown
Contributor Author

Nah! Closing this one.

@fdcastel fdcastel closed this Mar 29, 2026
@xoofx
Copy link
Copy Markdown
Owner

xoofx commented Mar 29, 2026

Nah! Closing this one.

I can release a package or wait for some other changes. Let me know.

@fdcastel
Copy link
Copy Markdown
Contributor Author

I can release a package or wait for some other changes. Let me know.

@xoofx I believe #140 was the last one I needed

If you could publish a new release, that would be fantastic! 🎉

@xoofx
Copy link
Copy Markdown
Owner

xoofx commented Mar 29, 2026

3.7.0 should be up!

@fdcastel
Copy link
Copy Markdown
Contributor Author

3.7.0 should be up!

Thanks man! Much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants