---
title: Argument resolution
summary: Parses and validates raw command-line arguments against the argument container's configured and auto-discovered resolvers.
status: draft
owner: <owner>
last_reviewed: 2026-09-15
library: SAIF.Framework.Windows
reference_type: package
operation_id: OP-WIN-003
trigger: Called by the program runner entry point (step 2 of Run()).
---

# Argument resolution

`ArgumentContainerBase<TArgumentContainer>.ResolveArguments()` binds the raw command-line arguments (already parsed into a dictionary by [command-line argument parsing](parse-command-line-arguments.md)) onto the argument container's properties, using explicit resolvers configured via `BuildArgumentResolvers` and reflection-driven auto-resolution for any remaining convertible property.

| Field | Value |
| --- | --- |
| **Operation ID** | OP-WIN-003 |
| **Trigger** | Called by [program runner entry point](program-runner-run.md) step 2. |
| **Inputs** | The raw `string[] args` supplied to the constructor, already parsed into `parsedArguments` (`Dictionary<string,string>`) via the container's `CommandLineParser`. |
| **Outputs** | A `ValidationResult` (`IsValid`, `Errors : IList<ValidationFailure>`). |
| **Primary components** | `ArgumentContainerBase<TArgumentContainer>.ResolveArguments()`, `HandleUnconfiguredArguments`, `ArgumentResolverBuilder<TArgumentContainer>`, `ArgumentResolver<TArgumentContainer, TArgument>` |
| **Entry point** | `Console\SAIF.Console\Console\Arguments\ArgumentContainerBase.cs` |

## Steps

1. Construct an `ArgumentResolverBuilder<TArgumentContainer>` bound to `CommandLineParser`'s parsed argument dictionary.
2. Call `BuildArgumentResolvers(builder)` — a protected virtual, app-specific method (no-op by default) where the consuming argument container explicitly sets up resolvers via `HasPropertyConfiguration`/`Setup<TArgument>`.
3. `HandleUnconfiguredArguments(builder)` — for every settable property on the argument container not already configured by step 2:
   - If the property type implements `IConvertible`: dynamically construct a resolver via reflection (`BuilderSetupMethod.MakeGenericMethod`) and add it to the resolver set ([BR-WIN-007](../business-rules.md#br-win-007-convertible-properties-auto-register)).
   - If the property type does not implement `IConvertible`: add `ValidationFailure("{PropertyName} cannot be implicitly converted so it must be explicitly configured.")` ([BR-WIN-008](../business-rules.md#br-win-008-non-convertible-unconfigured-properties-fail-validation)).
   - This is enforced overall by [BR-WIN-002](../business-rules.md#br-win-002-unconfigured-argument-properties-must-be-convertible-or-explicitly-configured): there is no silent-skip path for any settable property.
4. For each resolver in `builder.GetResolvers()`, call `TryResolveArgument(container, parsedArguments, errors)`:
   - If the argument is required (the `ArgumentResolver` default, not overridden via `NotRequired()`) and absent from the parsed dictionary: add `ValidationFailure("{argumentName} is missing.")`; property left unset ([BR-WIN-009](../business-rules.md#br-win-009-missing-required-arguments-fail-validation)).
   - If the argument is present but its configured `propertyValueParser` conversion throws in `AssignArgumentValue`: add `ValidationFailure("{name} '{value}' is not a valid {type}.")`; property left unset ([BR-WIN-010](../business-rules.md#br-win-010-argument-value-conversion-failures-fail-validation)).
   - Otherwise: assign the converted value to the bound property.
5. Return the accumulated `ValidationResult`.

## Process flow

The following diagram visualizes this operation's control flow.

```mermaid
flowchart TD
	Start([ResolveArguments called]) --> Build[BuildArgumentResolvers]
	Build --> Unconfigured[HandleUnconfiguredArguments]
	Unconfigured --> Convertible{Property IConvertible?}
	Convertible -->|Yes| AutoResolver[Auto-register resolver]
	Convertible -->|No| Fail1([ValidationFailure: must be explicitly configured])
	AutoResolver --> TryResolve[TryResolveArgument per resolver]
	TryResolve --> Present{Argument present?}
	Present -->|No, required| Fail2([ValidationFailure: argument missing])
	Present -->|Yes| Convert{Conversion succeeds?}
	Convert -->|No| Fail3([ValidationFailure: not a valid type])
	Convert -->|Yes| Assign([Property assigned])
	Fail1 --> Result([Return ValidationResult])
	Fail2 --> Result
	Fail3 --> Result
	Assign --> Result
```

## Failure and edge-case behavior
- A property configured as `NotRequired()` (or `NotRequired(defaultValue)`) that is absent from the command line does not produce a validation failure.
- Multiple validation failures across different properties/resolvers all accumulate into the same `ValidationResult.Errors` collection rather than short-circuiting on the first failure.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)

## Sources
- `Console\SAIF.Console\Console\Arguments\ArgumentContainerBase.cs`
- `Console\SAIF.Console\Console\Arguments\ArgumentResolver.cs`
- `Console\SAIF.Console\Console\Arguments\ArgumentResolverBuilder.cs`
- `Console\SAIF.Console\Console\Arguments\IArgumentResolver.cs`
