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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions