Skip to content

Constructor Binding + [DynamoMapperConstructor] #49

@j-d-ha

Description

@j-d-ha

Priority: P2 - Important
Tier: 3 - Advanced Features
Effort: Medium/Large (8-14 hours)

Already In Codebase

  • FromItem generation currently always uses an object initializer (parameterless construction): src/LayeredCraft.DynamoMapper.Generators/Templates/Mapper.scriban.
  • The property analyzer currently does not distinguish init-only vs regular setters (it only checks SetMethod != null): src/LayeredCraft.DynamoMapper.Generators/PropertyMapping/PropertyAnalyzer.cs.

Goal

Improve FromItem generation to support constructing target objects via constructors when needed, with a deterministic selection policy and an explicit override attribute.

Rules

  1. Prefer property assignment when possible.
  2. If constructors are required/used, select a constructor as follows:
    • If exactly one constructor is marked with [DynamoMapperConstructor], use it.
    • Else use the constructor with the most parameters ("widest").
    • If multiple constructors tie for widest, emit a diagnostic.
  3. Constructor parameters must be bindable to mapped members (by name) and mappable types.

New runtime API

Add a runtime attribute:

  • DynamoMapperConstructorAttribute
    • Target: constructors
    • Usage: marks which constructor to use

Implementation notes

  • Generator changes:
    • Extend model analysis to inspect constructors on the target model type.
    • Implement a binder that maps constructor parameters -> properties/fields (by name).
    • Generate new TargetType(arg1, arg2, ...) instead of object initializer when using constructor.
    • After construction, still assign any remaining settable non-init-only properties.
    • Init-only properties must be set during construction (not after). This likely requires checking propertySymbol.SetMethod.IsInitOnly.

Diagnostics

  • Multiple constructors marked with [DynamoMapperConstructor].
  • No usable constructor found for required init-only members.
  • Ambiguous widest constructors.
  • Constructor parameter cannot be bound.

Tests

Add verify tests in test/LayeredCraft.DynamoMapper.Generators.Tests/ covering:

  • Multiple constructors, widest chosen
  • [DynamoMapperConstructor] overrides widest
  • Init-only properties require constructor binding
  • Ambiguous widest constructors -> diagnostic

Acceptance criteria

  • Constructor selection is deterministic and follows the rules above.
  • Init-only properties are handled correctly (construction-time only).
  • Diagnostics are emitted for ambiguous/invalid constructor scenarios.
  • Snapshot tests verify generated code.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions