Prefer the exact type when resolving a member converter - #1859
Merged
Conversation
GetMemberConverter walked the registrations and took the first whose type was assignable from the declaring type, so a converter registered for a base type or an interface permanently shadowed a more specific one that happened to be registered later. The exact declaring type is now looked up first, with the assignable walk as the fallback, mirroring TryGetScrubOrIgnoreByMemberOfType.
SimonCropp
force-pushed
the
fix-memberconverter-exact-type
branch
from
August 17, 2026 12:54
402ac6c to
194ca7e
Compare
This was referenced Aug 26, 2026
This was referenced Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
VerifierSettings.GetMemberConverterwalked the registrations and returned the first entry whose type wasIsAssignableFromthe member's declaring type. Dictionary order is registration order, so a converter registered for a base type or an interface permanently shadowed a more specific one registered after it — the specific registration silently did nothing.The exact declaring type is now looked up first, with the assignable walk kept as the fallback. That mirrors
TryGetScrubOrIgnoreByMemberOfType, which already checks the exact type before scanning. Anulldeclaring type returns early, matching what the old loop did for it (IsAssignableFrom(null)is false for every entry).Test
SerializationTests.MemberConverterExactTyperegisters an interface converter first and a converter for one implementation second, then verifies both an instance of that implementation and an instance of a second implementation with no registration of its own — pinning that the exact type wins and the interface fallback still applies. It fails onmain, where both render the interface's output.Verify.Tests(1300) andStaticSettingsTestspass.