Add a parse method wrapper and caching to fix AoT compilation#1103
Conversation
There was a problem hiding this comment.
Pull request overview
This PR introduces a new HasParseMethod/Parse API on ITypeInspector (and corresponding plumbing in the inspector wrappers, composite inspector, cache inspector, and static source generator) to support string-to-type parsing in a way that is intended to be more AoT/trimming-friendly.
Changes:
- Adds
HasParseMethod(Type)andParse(string, Type)toITypeInspectorandTypeInspectorSkeleton, and threads them through the existing type inspector wrappers. - Implements reflection-based parse discovery/invocation in
ReflectionTypeInspectorand addsHasParseMethodcaching inCachedTypeInspector. - Updates the static source generator to emit
HasParseMethod/Parseimplementations, and adjusts the Core7 AoT compile test to use an underscored naming convention.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| YamlDotNet/Serialization/ITypeInspector.cs | Adds new parse-related APIs and documentation. |
| YamlDotNet/Serialization/TypeInspectors/TypeInspectorSkeleton.cs | Makes parse-related APIs abstract on the skeleton base. |
| YamlDotNet/Serialization/TypeInspectors/ReflectionTypeInspector.cs | Adds reflection-based HasParseMethod/Parse implementation. |
| YamlDotNet/Serialization/TypeInspectors/CachedTypeInspector.cs | Adds caching for HasParseMethod. |
| YamlDotNet/Serialization/TypeInspectors/CompositeTypeInspector.cs | Aggregates parse support across multiple inspectors. |
| YamlDotNet/Serialization/TypeInspectors/NamingConventionTypeInspector.cs | Delegates new APIs to wrapped inspector. |
| YamlDotNet/Serialization/TypeInspectors/ReadableAndWritablePropertiesTypeInspector.cs | Delegates new APIs to wrapped inspector. |
| YamlDotNet/Serialization/YamlAttributesTypeInspector.cs | Delegates new APIs to wrapped inspector. |
| YamlDotNet.Analyzers.StaticGenerator/StaticTypeInspectorFile.cs | Generates parse support in the static inspector source output. |
| YamlDotNet.Core7AoTCompileTest/Program.cs | Updates AoT compile test builder/sample YAML for underscored naming. |
| YamlDotNet/Serialization/Utilities/ReflectionTypeConverter.cs | Removes an extraneous whitespace-only line. |
Comments suppressed due to low confidence (4)
YamlDotNet/Serialization/TypeInspectors/ReflectionTypeInspector.cs:86
- Parse invokes the reflected Parse method via MethodInfo.Invoke but does not unwrap TargetInvocationException like other conversion paths do (e.g., TypeConverter.ChangeType). This changes the exception surface for consumers by wrapping parse failures. Consider catching TargetInvocationException and rethrowing the InnerException when present for consistency.
public override object? Parse(string value, Type expectedType)
{
var method = expectedType.GetMethod("Parse", [typeof(string)]);
if (method == null)
{
throw new InvalidOperationException($"Type '{expectedType.FullName}' does not have a static Parse method.");
}
return method.Invoke(null, new object[] { value });
}
YamlDotNet/Serialization/TypeInspectors/ReflectionTypeInspector.cs:83
- The error message uses expectedType.FullName, which can be null for some Type instances (e.g., generic parameters). Using expectedType.ToString() (or a fallback when FullName is null) would make the exception message reliably informative.
if (method == null)
{
throw new InvalidOperationException($"Type '{expectedType.FullName}' does not have a static Parse method.");
}
YamlDotNet/Serialization/TypeInspectors/CompositeTypeInspector.cs:102
- CompositeTypeInspector.Parse throws ArgumentOutOfRangeException when no inspector supports the type, but this isn't a range/argument validation problem; it's an unsupported operation/configuration issue. Consider throwing InvalidOperationException or NotSupportedException (and include a stable type name fallback if FullName is null).
if (parsableInspector == null)
{
throw new ArgumentOutOfRangeException(nameof(expectedType), $"No inspector with a Parse method for type {expectedType.FullName} was found.");
}
YamlDotNet/Serialization/ITypeInspector.cs:79
- The XML doc comment for Parse has malformed
formatting ("///
Converts...") which can degrade generated documentation. Align it with the surrounding style by putting the summary text on its own line between
and
.
/// <summary> Converts a string to an instance of the specified type using a static Parse method.
/// </summary>
/// <param name="value">The string value to convert.</param>
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Updated [Discord.Net](https://github.com/discord-net/Discord.Net) from 3.19.1 to 3.20.1. <details> <summary>Release notes</summary> _Sourced from [Discord.Net's releases](https://github.com/discord-net/Discord.Net/releases)._ ## 3.20.1 ## [3.20.1] - 2026-06-07 This release fixes a regression introduced in 3.20.0 ### Fixed - #3276 Handle null VoiceChannel in SocketVoiceState constructor (61ed916) **Full Changelog**: discord-net/Discord.Net@3.20.0...3.20.1 ## 3.20.0 ## [3.20.0] - 2026-06-06 This release brings support for checkboxes and checkbox/radio groups in modals, and also covers the "new" message search endpoint. ### Breaking changes - `SelectMenuOptionAttribute` from the Interaction Framework was renamed to `EnumOptionAttribute`. ### Added - #3232 IF modal radio buttons, and checkboxes (c95fbf6) - #3268 add support for getting messages from a guild (with filters) (31fed25) - #3255 add missing audit log action types (4476eea) - #3265 Add GET voice-state REST wrappers (13d83da) ### Fixed - #3258 propagate parent module attributes to child commands (cbc61d9) - #3263 strip RTP padding before DAVE decrypt (RFC 3550 В§5.1) (1a843fb) - #3256 Add empty payload check (6527e71) - #3264 Fix reference to PreCompiledLambdas/UseCompiledLambda (763aa79) - #3271 fix for #3269 (9abfbfd) - #3272 Fix default array converter in modals & add docs for checkboxes/radio groups (527764c) ### Misc - #3254 user `global_name` description (05af64b) - #3257 feat(Core): add missing JSON error codes (4272ae1) - #3259 refactor(Core): rename JSON error code (504e1db) - #3261 Message call data timestamp nullability (5a328a0) - #3266 Add play audio sample (4d8b0bc) ## New Contributors * @Archivelit made their first contribution in discord-net/Discord.Net#3256 * @Sim-hu made their first contribution in discord-net/Discord.Net#3255 * @yury-opolev made their first contribution in discord-net/Discord.Net#3263 * @apartje made their first contribution in discord-net/Discord.Net#3271 **Full Changelog**: discord-net/Discord.Net@3.19.1...3.20.0 Commits viewable in [compare view](discord-net/Discord.Net@3.19.1...3.20.1). </details> Updated [DotNetEnv](https://github.com/tonerdo/dotnet-env) from 3.1.1 to 3.2.0. <details> <summary>Release notes</summary> _Sourced from [DotNetEnv's releases](https://github.com/tonerdo/dotnet-env/releases)._ ## 3.2.0 - Switch parsing to Superpower (from Sprache) - Fix utf8 parsing - Interpolated variables parsing Commits viewable in [compare view](tonerdo/dotnet-env@v3.1.1...v3.2.0). </details> Updated [YamlDotNet](https://github.com/aaubry/YamlDotNet) from 16.3.0 to 18.1.0. <details> <summary>Release notes</summary> _Sourced from [YamlDotNet's releases](https://github.com/aaubry/YamlDotNet/releases)._ ## 18.1.0 ## What's Changed * Use NET 10 with benchmarks by @mcraiha in aaubry/YamlDotNet#1099 * Revert package upgrades by @EdwardCooke in aaubry/YamlDotNet#1104 * Added default maximum recursion level of 130 (max when using defaults on Windows/.net8) by @EdwardCooke in aaubry/YamlDotNet#1110 * Static deserializer builder needed the default maximum recursion by @EdwardCooke in aaubry/YamlDotNet#1111 ## New Contributors * @mcraiha made their first contribution in aaubry/YamlDotNet#1099 **Full Changelog**: aaubry/YamlDotNet@v18.0.0...v18.1.0 ## Breaking * Maximum depth of yaml files is now 130 by default. If you need higher you will need to adjust the maximum yaml depth. Going above 130 runs the risk of stack overflow exceptions when any exception happens inside of the deserialization ## 18.0.0 ## What's Changed * Add a parse method wrapper and caching to fix AoT compilation by @EdwardCooke in aaubry/YamlDotNet#1103 **BREAKING CHANGE** This is a breaking change in the `TypeInspectorSkeleton` class and the `ITypeInspector` interface by adding 2 methods . Quick fix to resolve those breaking changes in your own custom TypeInspector is to return false on the HasParseMethod method and return null or throw an exception on the Parse method. **Full Changelog**: aaubry/YamlDotNet@v17.1.0...v18.0.0 ## 17.1.0 ## What's Changed * Security improvements by @EdwardCooke in aaubry/YamlDotNet#1102 There was a potential breaking change for large yaml files in the MergingParser. You may need to specify the optional parameter for maximum events to be processed. It default to 100k events which is a very large yaml file. **Full Changelog**: aaubry/YamlDotNet@v17.0.0...v17.1.0 ## 17.0.0 ## What's Changed * Clean-up the "IsKey" logic by @aaubry in aaubry/YamlDotNet#1073 * Fix for gitversion and pinning it so it doesnt break...again. by @EdwardCooke in aaubry/YamlDotNet#1074 * Add max depth handling to StaticDeserializerBuilder (builds on #1072) by @skdishansachin in aaubry/YamlDotNet#1082 * Allow specifying a maximum recursion for the deserializer by @aaubry in aaubry/YamlDotNet#1072 * Fix NullReferenceException when serializing null System.Type properties by @fdcastel in aaubry/YamlDotNet#1091 * Reduce code duplication in converters and event emitters by @fdcastel in aaubry/YamlDotNet#1090 * Use pre-compiled static Regex instances in ScalarNodeDeserializer by @fdcastel in aaubry/YamlDotNet#1088 * Fix infinite loop in source generator exception handler by @fdcastel in aaubry/YamlDotNet#1087 * Fix TODOs, typos, and add missing tests by @fdcastel in aaubry/YamlDotNet#1086 * Fix YamlException.ToString() to include stack trace by @skdishansachin in aaubry/YamlDotNet#1084 * Fix remaining spec cases during parsing: L383, C2SP by @am11 in aaubry/YamlDotNet#1081 * Improve type fidelity in UnquotedStringTypeDeserialization test by @jhgbrt in aaubry/YamlDotNet#1076 * CodeQL Advanced Workflow by @aluty in aaubry/YamlDotNet#1067 * Nullable fixes in non-public code by @Kielek in aaubry/YamlDotNet#1064 * Use string interning by @simonthum in aaubry/YamlDotNet#1055 * Fix grammar in comments in DefaultValuesHandling.cs by @209jkjkjk in aaubry/YamlDotNet#1041 * fix #1031 by @dogdie233 in aaubry/YamlDotNet#1033 * Improve Native AOT Support (Closes #1085) by @fdcastel in aaubry/YamlDotNet#1092 ## New Contributors * @skdishansachin made their first contribution in aaubry/YamlDotNet#1082 * @fdcastel made their first contribution in aaubry/YamlDotNet#1091 * @jhgbrt made their first contribution in aaubry/YamlDotNet#1076 * @aluty made their first contribution in aaubry/YamlDotNet#1067 * @Kielek made their first contribution in aaubry/YamlDotNet#1064 * @simonthum made their first contribution in aaubry/YamlDotNet#1055 * @209jkjkjk made their first contribution in aaubry/YamlDotNet#1041 * @dogdie233 made their first contribution in aaubry/YamlDotNet#1033 **Full Changelog**: aaubry/YamlDotNet@v16.3.0...v17.0.0 Commits viewable in [compare view](aaubry/YamlDotNet@v16.3.0...v18.1.0). </details> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions </details> Signed-off-by: dependabot[bot] <[email protected]> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Fixes #1098
This is a breaking change in the TypeInspectorSkeleton class and adds 2 methods to ITypeInspector. Quick fix to resolve those breaking changes in your own custom TypeInspector is to return
falseon theHasParseMethodmethod and returnnullor throw an exception on theParsemethod.