Skip to content

Diagnostics ​

Compiler diagnostics emitted by DesignPatterns source generators and analyzers. IDs are defined in DesignPatterns.Diagnostics.DiagnosticIds.

Help links in the IDE point to this page (#dp### anchors).

Singleton (DP001–DP002) ​

IDSeverityWhen
DP001Error[GenerateSingleton] target is not partial
DP002ErrorInvalid singleton target (must be sealed class with parameterless ctor)

Strategy (DP003–DP007) ​

IDSeverityWhen
DP003ErrorDuplicate strategy key
DP004ErrorImplementation does not match strategy contract
DP005—(reserved / handler overlap — see DP005 under Chain)
DP006InfoImplementation type not registered with [RegisterStrategy]
DP007ErrorStrategy implementation missing parameterless constructor

Chain of Responsibility (DP005, DP008–DP009, DP024) ​

IDSeverityWhen
DP005ErrorDuplicate [HandlerOrder] value
DP008ErrorHandler does not implement the pipeline contract
DP009ErrorHandler missing parameterless constructor
DP024InfoHandler type not registered with [HandlerOrder]

Composite (DP010–DP015) ​

IDSeverityWhen
DP010ErrorDuplicate composite part key
DP011ErrorUnknown parent key
DP012ErrorCycle in composite tree
DP013ErrorPart does not match node contract
DP014ErrorPart missing parameterless constructor
DP015ErrorRegistry holder missing [CompositeBuildable]

Decorator (DP016–DP019) ​

IDSeverityWhen
DP016ErrorDuplicate decorator order
DP017ErrorDecorator does not match contract
DP018ErrorType does not implement IDecorator<T>
DP019ErrorDecorator missing parameterless constructor

Factory Registry (DP020–DP023) ​

IDSeverityWhen
DP020ErrorDuplicate factory key
DP021ErrorFactory does not match product contract
DP022ErrorFactory missing parameterless constructor
DP023InfoProduct type not registered with [RegisterFactory]

Registry key (DP025) ​

IDSeverityWhen
DP025InfoString literal key passed to a generated Strategy or Factory registry lookup is not among registered keys

Where it applies: Get / TryGet / Create / TryCreate on IStrategyRegistry<,> / IFactoryRegistry<,> when the key argument is a string literal (not a {Contract}Keys constant).

Message: includes the contract type and the list of registered keys.

Fix: prefer {Contract}Keys.* constants. The CorrectRegistryKey CodeFix suggests the closest registered key when the typo is near a known key.

See also Registry key conventions.

Plugin assemblies (DP033) ​

IDSeverityWhen
DP033ErrorThe same strategy key for the same contract is registered in more than one referenced provider assembly

Where it applies: host (or any) compilations that reference multiple plugin provider assemblies contributing [RegisterStrategy] / [RegisterStrategy<TContract>] for the same contract with an identical key string.

Message: includes the key, contract type, and conflicting assembly names.

Fix: use distinct keys per provider assembly, or reference only one provider per contract dimension. Duplicate keys within a single assembly remain DP003 (generator).

See Plugin assemblies sample, the main repo PluginAssemblies.md, and Configuration.

State transition table (DP026–DP031) ​

IDSeverityWhen
DP026ErrorDuplicate (from state, trigger) edge
DP027Error[Transition] state value is not a declared enum member
DP028Error[Transition] trigger value is not a declared enum member
DP029Error[StateMachine] Initial is not a declared state enum member
DP030ErrorHolder class is not static partial
DP031InfoState enum member never appears as a [Transition] source (terminal/reserved hint)

See State transition table.

State guard (DP032, DP034–DP035) ​

IDSeverityWhen
DP032Error[Transition(Guard = nameof(Method))] guard method not found on holder class
DP034ErrorGuard method is not static (defensive — C# compiler rejects instance methods on static classes first)
DP035ErrorGuard method has wrong signature (must be static bool Method(TState, TTrigger))

State literal edge (DP036) ​

IDSeverityWhen
DP036InfoTryTransition called with literal (state, trigger) arguments that do not match any declared [Transition] edge

State entry/exit actions (DP037–DP039) ​

IDSeverityWhen
DP037Error[Transition(OnEnter/OnExit = nameof(Method))] action method not found on holder class
DP038ErrorAction method is not static (unreachable in practice — CS0708 fires first; retained for completeness)
DP039ErrorAction method has wrong signature (must be static void Method(TState, TState, TTrigger) or static ValueTask Method(TState, TState, TTrigger, CancellationToken))

Composite DI + Visitor (DP040–DP041) ​

IDSeverityWhen
DP040ErrorBuildRoot(IServiceProvider) called but a composite node is not registered in the container
DP041InfoGenerated I{Contract}NodeVisitor does not cover all node types (reserved — the C# compiler enforces full coverage via CS0535 when implementing the generated interface)

Decorator DI + async (DP042–DP043) ​

IDSeverityWhen
DP042ErrorAsync decorator method signature is incorrect (DecorateAsync must return ValueTask<TService>)
DP043ErrorAsync decorator cannot be resolved from DI when using Build(IServiceProvider, core)

EventAggregator (DP044–DP046) ​

IDSeverityWhen
DP044InfoType implements IEventHandler<T> but is not marked with [RegisterEventHandler]
DP045ErrorDuplicate [RegisterEventHandler] on the same handler for the same event type
DP046ErrorType marked with [RegisterEventHandler<T>] but does not implement IEventHandler<T>

Strategy guard (DP047–DP049) ​

IDSeverityWhen
DP047Error[RegisterStrategy(Guard = nameof(Method))] guard method not found on strategy class
DP048ErrorGuard method is not static
DP049ErrorGuard method has wrong signature (must be static bool Method(TKey))

Handler guard (DP050–DP052) ​

IDSeverityWhen
DP050Error[HandlerOrder(Guard = nameof(Method))] guard method not found on handler class
DP051ErrorGuard method is not static
DP052ErrorGuard method has wrong signature (must be static bool Method(TContext))

Factory async + pooling (DP053–DP055) ​

IDSeverityWhen
DP053Error[RegisterFactory(IsAsync = true)] but factory does not implement IAsyncFactory<T>
DP054ErrorPoolSize is negative (must be ≥ 0; 0 disables pooling)
DP055WarningPoolSize > 1024 (may cause excessive memory usage)

State hierarchy (DP056–DP059) ​

IDSeverityWhen
DP056ErrorA state hierarchy contains a cycle
DP057Error[StateParent] references a state that is not a member of the state enum
DP058Error[StateParent] declares a state as its own parent
DP059InfoA declared parent state has no children and no outgoing transitions

DI lifetime (DP060–DP062) ​

IDSeverityWhen
DP060WarningA generated registry lifetime exceeds the implementation lifetime and may capture a shorter-lived service
DP061InfoAn implementation lifetime exceeds the registry lifetime and may cause unnecessary instances
DP062WarningA Singleton service depends on a Scoped or Transient service

Composite tree schema (DP063–DP065) ​

IDSeverityWhen
DP063WarningA Composite tree exceeds the MaxDepth declared by [CompositeSchema]
DP064ErrorA Composite child type is not listed in the parent’s AllowedChildTypes
DP065WarningA Composite contract exceeds the MaxNodes declared by [CompositeSchema]

Singleton lifecycle (DP066–DP071) ​

IDSeverityWhen
DP066WarningA Singleton factory delegate resolves a Scoped or Transient service and captures it
DP067ErrorA GenerateSingleton asynchronous initializer is missing, non-static, or has an invalid Task/ValueTask signature
DP068WarningA generated singleton is also registered as a DI Singleton, creating two lifecycle owners
DP069InfoA non-thread-safe generated singleton contains mutable instance state
DP070InfoMutable static singleton state was detected; prefer an immutable Lazy-backed singleton or DI
DP071WarningMutable static singleton state is also registered as a DI Singleton

Code fixes ​

DesignPatterns.CodeFixes ships inside the Skymly.DesignPatterns meta package (analyzers/dotnet/cs). Selected diagnostics offer one-click fixes in the IDE (requires C# Workspaces):

DiagnosticCode fix (summary)
DP006Add [RegisterStrategy("key", typeof(TContract))]
DP023Add [RegisterFactory("key", typeof(TContract))]
DP024Add [HandlerOrder(order, typeof(TContext))]
DP025Replace literal with nearest registered key
DP001Add partial modifier
DP015Add [CompositeBuildable]
DP004 / DP013 / DP017 / DP021Add contract implementation
DP007 / DP009 / DP014 / DP019 / DP022Add parameterless constructor

Generator errors (DP001–DP005, DP007–DP022) are fixed by correcting attributes or types; no CodeFix is provided for duplicate-key errors.

Category prefix: DesignPatterns.

Released under the MIT License.