For types that are immutable or only expose parameterized constructors, PolyType uses the IConstructorShape abstraction. This allows you to construct new instances from scratch.
Construction is handled via an opaque, mutable token called TArgumentState. This state encapsulates all parameters required by the constructor. The process follows these steps:
- Initialize State: Call
GetArgumentStateConstructor() to get a default instance of the TArgumentState. - Populate State: Use
IParameterShape<TArgumentState, TParameterType>.GetSetter() to populate the state token with values. - Execute Constructor: Call
GetParameterizedConstructor() passing the populated state to create the final object.
Key Components:
IObjectTypeShape<T>.Constructor: Access the constructor shape for a type.IConstructorShape<TDeclaringType, TArgumentState>: Defines the state lifecycle and the final constructor call.IParameterShape<TArgumentState, TParameterType>: Provides setters to populate the TArgumentState token.TArgumentState: An opaque token (often a value tuple) representing the collection of constructor arguments.
// Example: Implementing a constructor shape for a record
record MyPoco(string y, int x = 42);
class MyPocoConstructorShape : IConstructorShape<MyPoco, (string, int)>
{
// Returns a default state: (null, 42)
public Func<(string, int)> GetArgumentStateConstructor() => () => (null!, 42);
// Creates the record from the state
public Func<(string, int), MyPoco> GetParameterizedConstructor() => state => new MyPoco(state.Item1, state.Item2);
}