Strategy.For<T>() reference
API surface, attribute reference, primitive mapping, and diagnostic codes for Strategy.For<T>() and the constraint attributes.
Strategy.For<T>()
Namespace: Conjecture.Core
Package: Conjecture.Core (bundled — no extra NuGet package)
// Returns the registered strategy for T.
public static Strategy<T> For<T>();
// Returns the registered strategy for T with property overrides applied.
public static Strategy<T> For<T>(Action<ForConfiguration<T>> configure);
T must be decorated with [Arbitrary]. If no provider is registered, a CON312 error is raised at the call site.
ForConfiguration<T>
Passed to the configure callback in Strategy.For<T>(cfg => ...).
Override<TProp>
public ForConfiguration<T> Override<TProp>(
Expression<Func<T, TProp>> selector,
Strategy<TProp> strategy);
Replaces the strategy for the property identified by selector with strategy. Multiple overrides can be chained; all other properties use their generated defaults.
Strategy<Order> orders = Strategy.For<Order>(cfg => cfg
.Override(o => o.Total, Strategy.Decimals(0m, 999.99m))
.Override(o => o.Customer, Strategy.Strings(minLength: 1)));
Constraints:
selectormust be a simple member-access expression (e.g.,o => o.Total). Nested access and method calls are not supported.- The
TPropof the override must match the property's declared type exactly.
Constraint attributes
Constraint attributes are applied to constructor parameters or init properties of [Arbitrary] types. The source generator reads them at compile time.
[StrategyRange]
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public sealed class StrategyRangeAttribute(double min, double max) : Attribute
Constrains the generated range for a numeric parameter to [min, max]. Applies to int, long, short, byte, uint, ulong, ushort, sbyte, float, double, and decimal.
[Arbitrary]
public partial record Product(
[StrategyRange(0.01, 9_999.99)] decimal Price,
[StrategyRange(1, 500)] int Quantity);
[StrategyStringLength]
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public sealed class StrategyStringLengthAttribute(int minLength, int maxLength) : Attribute
Constrains the length of generated strings to [minLength, maxLength].
[Arbitrary]
public partial record Customer(
[StrategyStringLength(1, 100)] string Name,
[StrategyStringLength(5, 254)] string Email);
[StrategyRegex]
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property)]
public sealed class StrategyRegexAttribute(string pattern) : Attribute
Constrains generated strings to match pattern. Requires the Conjecture.Regex package.
[Arbitrary]
public partial record PhoneNumber(
[StrategyRegex(@"^\+\d{7,15}$")] string Value);
If Conjecture.Regex is not referenced, the generator emits CON202 and falls back to unconstrained strings.
[StrategyMaxDepth]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public sealed class StrategyMaxDepthAttribute(int maxDepth) : Attribute
Applied to the type (not a parameter) to cap recursive generation depth. Required on self-referential or mutually recursive types; optional on non-recursive types.
[Arbitrary]
[StrategyMaxDepth(4)]
public partial class TreeNode
{
public TreeNode(int Value, TreeNode? Left, TreeNode? Right) { /* ... */ }
}
At depth 0, nullable recursive parameters produce null (leaf nodes). At depth > 0, recursion continues up to the cap.
Default depth when the attribute is absent: 5.
Primitive type → default strategy mapping
| Parameter type | Generated strategy |
|---|---|
bool |
Strategy.Booleans() |
byte, short, int, long |
Strategy.Integers<T>() (full range) |
uint, ulong, ushort, sbyte |
Strategy.Integers<T>() (full range) |
float |
Strategy.Floats() |
double |
Strategy.Doubles() |
decimal |
Strategy.Decimals() |
string |
Strategy.Strings() (length 0–20, printable ASCII) |
char |
Strategy.Chars() |
Guid |
Strategy.Guids() |
DateTime |
Strategy.DateTimes() |
DateTimeOffset |
Strategy.DateTimeOffsets() |
DateOnly |
Strategy.DateOnlyValues() |
TimeOnly |
Strategy.TimeOnlyValues() |
TimeSpan |
Strategy.TimeSpans() |
T? (value type) |
Strategy.Nullable(inner) |
T? (reference type) |
inner.OrNull() (~10% null probability) |
Enum T |
Strategy.Enums<T>() |
[Arbitrary] type |
Strategy.For<T>() (nested) |
[StrategyRange], [StrategyStringLength], and [StrategyRegex] override the defaults for the individual parameter they are applied to.
Supported collection types
| Parameter type | Generated strategy |
|---|---|
List<T> |
Strategy.Lists(inner) |
IReadOnlyList<T> |
Strategy.Lists(inner) |
IList<T> |
Strategy.Lists(inner) |
IEnumerable<T> |
Strategy.Lists(inner) |
T[] |
Strategy.Lists(inner).Select(l => l.ToArray()) |
IReadOnlySet<T>, HashSet<T> |
Strategy.Sets(inner) |
IReadOnlyDictionary<K,V>, Dictionary<K,V> |
Strategy.Dictionaries(keyInner, valueInner) |
Collection size defaults to 0–100 elements. Apply [StrategyRange] to a List<T> parameter to constrain the element count.
Strategy.For<T>() call-site diagnostics
These diagnostics fire at the Strategy.For<T>() or [From<T>] call site, not on the type declaration.
CON310 — target is an interface
Severity: Error
Strategy.For<T>() cannot generate a strategy for an interface type. Apply [Arbitrary] to each concrete implementation and use Strategy.OneOf(...) to combine them.
// Error:
Strategy<IShape> shapes = Strategy.For<IShape>(); // CON310
// Fix: use concrete types
Strategy<IShape> shapes = Strategy.OneOf(
Strategy.For<Circle>().Select(c => (IShape)c),
Strategy.For<Rectangle>().Select(r => (IShape)r));
CON311 — abstract type with no [Arbitrary] subtypes
Severity: Error
The type is abstract but has no concrete subtypes decorated with [Arbitrary] in the compilation.
// Error:
[Arbitrary]
public abstract partial class Animal { }
Strategy<Animal> animals = Strategy.For<Animal>(); // CON311
// Fix: add [Arbitrary] to at least one concrete subtype
[Arbitrary]
public partial class Dog : Animal { }
CON312 — no registered provider
Severity: Error
Strategy.For<T>() was called for a type that has no [Arbitrary] attribute and therefore no registered IStrategyProvider<T>.
// Error:
public class Widget { }
Strategy<Widget> widgets = Strategy.For<Widget>(); // CON312
// Fix: add [Arbitrary] and make the type partial
[Arbitrary]
public partial class Widget { }
CON313 — mutual recursion without [StrategyMaxDepth]
Severity: Warning
Two or more [Arbitrary] types reference each other without either having [StrategyMaxDepth]. Generation may be very deep or diverge.
// Warning — CON313:
[Arbitrary]
public partial record Parent(Child? Child);
[Arbitrary]
public partial record Child(Parent? Parent);
// Fix: add [StrategyMaxDepth] to at least one side
[Arbitrary]
[StrategyMaxDepth(3)]
public partial record Parent(Child? Child);
See also
- How to use Strategy.For<T>() — step-by-step recipes
- Understanding Strategy.For<T>() source generation — design rationale and registry mechanics
- Reference: Analyzers — CON200–CON202, CON205, CON300–CON302 (type-declaration diagnostics)
- Reference: Attributes —
[Arbitrary],[From<T>],[FromMethod]