Skip to content

Construct records and immutable types through their constructor - #6

Merged
holonsoftFounder merged 1 commit into
mainfrom
feature/constructor-resolution
Sep 9, 2026
Merged

Construct records and immutable types through their constructor#6
holonsoftFounder merged 1 commit into
mainfrom
feature/constructor-resolution

Conversation

@holonsoftFounder

Copy link
Copy Markdown
Member

Summary

  • CtorSource<T> now picks the constructor once the registered members are known and feeds parameters from the members with the same name (case-insensitive) and a compatible type. Records need no parameterless constructor anymore, get-only properties of immutable classes are populated through the constructor.
  • New ConstructorResolver (Util) and IMemberBoundFactory (Engine.Interfaces): the ObjectBuilder hands the member sources to the factory and skips the set actions of consumed members. Preference: most members that cannot be set otherwise, then fewest parameters, then most matches. Ordinary classes keep their parameterless constructor and setters, no change for them.
  • DefaultTypeConvention registers get-only properties that match a constructor parameter, so member conventions apply to them. ApplyTypeFactoryAction falls back to CtorSource<T> for concrete classes (was DefaultSource<T> / Activator).
  • Unmatched parameters: declared default, else default of the value type, else an object from the session generated one level deeper (recursion limit honored, fixes potential infinite recursion for self referencing constructor parameters). Structs without any bound member stay default: an unconfigured DateOnly parameter no longer throws.
  • Get-only property with a data source but no matching constructor parameter throws InvalidOperationException naming the property (was a reflection error at generation time).
  • new CtorSource<T>(constructorInfo) still pins a constructor and takes matching members. Nullable annotations apply to constructor arguments. Impose/Source(...) at generation time keep working on positional record properties.
  • README section, PackageReleaseNotes, demo comments.

Test plan

  • 52 new or rewritten tests: resolver rules, CtorSource binding/pinning/defaults/recursion/structs/ParentSource, convention and factory fallback expectations, ObjectBuilder consumption and error, integration for records with and without conventions, immutable classes, partial setup, parameterless preference, declared defaults, Impose/Source, nullable annotations, self referencing record, list demo without parameterless ctor
  • dotnet build -c Release zero warnings
  • 759 tests green per framework on net8, net9, net10 (Windows)
  • Manual run of a file based app: nested record through ctor, get-only class through ctor, referrer chain terminates at the recursion limit

🤖 Generated with Claude Code

CtorSource<T> picks the constructor once the registered members are known and
feeds parameters from the members with the same name and a compatible type
(ConstructorResolver, IMemberBoundFactory). The object builder hands the member
sources to the factory and does not set consumed members again. Preference:
most members that cannot be set otherwise, then fewest parameters, so ordinary
classes keep their parameterless constructor. DefaultTypeConvention registers
get-only properties that match a constructor parameter, the factory fallback
uses CtorSource for concrete classes. Unmatched parameters get their declared
default, the default of their value type, or a session generated object one
level deeper so recursive constructor parameters honor the recursion limit;
structs without bound members stay default. Get-only members without a
constructor parameter throw a clear message. Nullable annotations apply to
constructor arguments. Tests, README and release notes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@holonsoftFounder
holonsoftFounder merged commit ad35a95 into main Sep 9, 2026
2 checks passed
@holonsoftFounder
holonsoftFounder deleted the feature/constructor-resolution branch September 9, 2026 08:07
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.

1 participant