You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A capability scope with a strongly-typed owner. The owner is immutable and set at construction time, providing compile-time type safety for all owner operations.
Constructors
Constructor
Description
CapabilityScope(TOwner owner)
Creates a new typed scope with the specified owner
Creates a new typed scope with the specified owner and options
Properties
Property
Type
Description
Owner
ScopeOwnerApi<TOwner>
Provides access to strongly-typed owner operations
Composers
ComposerRegistryApi
Provides access to the composer registry (inherited)
Compositions
CompositionRegistryApi
Provides access to the composition registry (inherited)
Anchors
ScopeAnchorsApi
Provides access to anchor management operations (inherited)
Example
// Create a typed scope with ownervarconfigManager=newConfigurationManager();usingvarscope=newCapabilityScope<ConfigurationManager>(configManager);// Owner methods are strongly typed - no generic parameter needed!varowner=scope.Owner.Get();// Returns ConfigurationManager directlyvarcomposer=scope.Owner.Compose();// Composes for the owner// With optionsvaroptions=newCapabilityScopeOptions{UseComposerRegistry=true};usingvartypedScope=newCapabilityScope<ConfigManager>(config,options);// Can be used as base CapabilityScopeCapabilityScopebaseScope=scope;
Inheritance
CapabilityScope<TOwner> inherits from CapabilityScope, so it can be used anywhere a base CapabilityScope is expected. This enables patterns like:
Provides scope ownership management operations. Owners are single-valued context objects associated with a scope (e.g., user, request, pipeline). Each scope can have at most one owner.
Access via scope.Owner.*
Properties
Property
Type
Description
Scope
CapabilityScope
Returns the associated scope (for fluent chaining back to scope)
Methods
Method
Returns
Description
Set(object owner)
ScopeOwnerApi
Sets the owner for the scope (throws if already set)
Replace(object owner)
ScopeOwnerApi
Replaces the existing owner with a new one
Get<T>()
T
Gets the owner cast to type T, throws if not set or wrong type
GetOrThrow<T>()
T
Alias for Get<T>()
TryGet<T>(out T? owner)
bool
Tries to get the owner as type T, returns true if successful
Compose(bool? useRegistry = null)
Composer
Creates a composer for the owner
ComposeFor<T>(bool? useRegistry = null)
Composer
Creates a composer for the owner if it's of type T
GetComposition()
Composition?
Gets the existing composition for the owner, or null
TryGetComposition(out Composition? composition)
bool
Tries to get the composition, returns true if found
GetCompositionFor<T>()
Composition?
Gets the composition if owner is of type T, or null
GetRequiredComposition()
Composition
Gets the composition, throws if not found
GetRequiredCompositionFor<T>()
Composition
Gets the composition if owner is type T, throws if not found
GetComposer()
Composer?
Gets the composer from registry, or null
TryGetComposer(out Composer? composer)
bool
Tries to get the composer from registry, returns true if found
GetComposerFor<T>()
Composer?
Gets the composer if owner is of type T, or null
GetRequiredComposer()
Composer
Gets the composer from registry, throws if not found
GetRequiredComposerFor<T>()
Composer
Gets the composer if owner is type T, throws if not found
Exceptions
Method
Exception
Condition
All methods
ObjectDisposedException
If scope is disposed
Set
InvalidOperationException
If owner is already set
Replace
InvalidOperationException
If owner is not set
GetOrThrow
InvalidOperationException
If owner is not set
Compose
InvalidOperationException
If owner is not set
Example
usingvarscope=newCapabilityScope();// Set owner oncescope.Owner.Set(currentUser);// Get owner (various patterns)varowner=scope.Owner.Get();varrequiredOwner=scope.Owner.GetOrThrow();if(scope.Owner.TryGet(outvaro)){/* use o */}// Replace owner (runtime replacement scenario)scope.Owner.Replace(newUser);// Compose capabilities for ownervarcomposition=scope.Owner.Compose(c =>c.Add(newUserPermissions()).Add(newAuditLog()));// Fluent chaining back to scopescope.Owner.Set(currentUser).Scope.Anchors.Set<ILogger>(logger);
ScopeOwnerApi<TOwner>
Provides strongly-typed owner operations for CapabilityScope<TOwner>. All methods work with the concrete owner type without needing generic parameters.
Access via scope.Owner on a CapabilityScope<TOwner> instance.
Properties
Property
Type
Description
Scope
CapabilityScope
Returns the associated scope
Methods
Method
Returns
Description
Get()
TOwner
Gets the owner (always succeeds since owner is immutable)
TryGet(out TOwner? owner)
bool
Gets the owner (always returns true)
Compose(bool? useRegistry = null)
Composer
Creates a composer for the owner
GetComposition()
Composition?
Gets the existing composition for the owner, or null
TryGetComposition(out Composition? composition)
bool
Tries to get the composition, returns true if found
GetRequiredComposition()
Composition
Gets the composition, throws if not found
GetComposer()
Composer?
Gets the composer from registry, or null
TryGetComposer(out Composer? composer)
bool
Tries to get the composer from registry, returns true if found
GetRequiredComposer()
Composer
Gets the composer from registry, throws if not found
Exceptions
Method
Exception
Condition
All methods
ObjectDisposedException
If scope is disposed
GetRequiredComposition()
InvalidOperationException
If no composition exists
GetRequiredComposer()
InvalidOperationException
If no composer in registry
Example
varconfig=newConfigurationManager();usingvarscope=newCapabilityScope<ConfigurationManager>(config);// No generic parameter needed!varowner=scope.Owner.Get();// Returns ConfigurationManagervarcomposer=scope.Owner.Compose();// Try-patternif(scope.Owner.TryGetComposition(outvarcomposition)){// Use composition}// Build and retrievescope.Owner.Compose().Add(newConfigCapability("key","value")).Build();varcomp=scope.Owner.GetRequiredComposition();
ScopeAnchorsApi
Provides scope anchor management operations. Anchors are keyed context objects associated with a scope (e.g., logger, configuration, pipeline). Use typed anchors for compile-time safety or named anchors for string keys.
Access via scope.Anchors.*
Properties
Property
Type
Description
Scope
CapabilityScope
Returns the associated scope (for fluent chaining back to scope)
Methods - Typed Anchors
Method
Returns
Description
Set<T>(T anchor)
ScopeAnchorsApi
Sets a typed anchor (throws if already set)
Get<T>()
T?
Gets a typed anchor, or null/default if not set
GetOrThrow<T>()
T
Gets a typed anchor, throws if not set (alias: Require<T>())
TryGet<T>(out T anchor)
bool
Tries to get a typed anchor, returns true if successful
ComposeFor<T>(bool? useRegistry = null)
Composer
Creates a composer for a typed anchor (throws if not set)
GetCompositionFor<T>()
Composition?
Gets the existing composition for a typed anchor, or null
Tries to get the primary capability as a specific type
Exceptions
Method
Exception
Condition
GetPrimary()
InvalidOperationException
If no primary capability exists
GetRequiredPrimaryAs<T>()
InvalidOperationException
If primary capability doesn't exist or isn't of the specified type
GetRequiredFirst<T>()
InvalidOperationException
If no capability of the specified type exists
GetRequiredLast<T>()
InvalidOperationException
If no capability of the specified type exists
Example
// Query capabilitiesvarvalidators=composition.GetAll<IValidator>();varhasLogging=composition.Has<ILogger>();// Get first capability (convenient when you expect only one)varconfig=composition.GetFirstOrDefault<ConfigCapability>();if(config!=null){// Use config}// Or use Try patternif(composition.TryGetFirst<ConfigCapability>(outvarcfg)){// Use cfg}// Work with primaryif(composition.TryGetPrimary(outvarprimary)){Console.WriteLine($"Primary: {primary}");}// Type-safe primary accessvaruserPrimary=composition.GetRequiredPrimaryAs<UserPrimaryCapability>();
Using Extensions
Fluent extension methods for inline capability usage. These are convenience wrappers over the Get* methods that enable chainable, expressive usage patterns.
Extension methods on IComposition
Single Instance Methods (First)
Method
Returns
Description
UsingFirst<T>(Action<T> use)
IComposition
Uses the first T capability; throws if none exist. Chainable.
UsingFirst<T, TResult>(Func<T, TResult> use)
TResult
Uses the first T capability and returns a result; throws if none exist
UsingFirstOrDefault<T>(Action<T> use)
IComposition
Uses the first T capability if it exists; silent if missing. Chainable.
Single Instance Methods (Last)
Method
Returns
Description
UsingLast<T>(Action<T> use)
IComposition
Uses the last T capability; throws if none exist. Chainable.
UsingLast<T, TResult>(Func<T, TResult> use)
TResult
Uses the last T capability and returns a result; throws if none exist
UsingLastOrDefault<T>(Action<T> use)
IComposition
Uses the last T capability if it exists; silent if missing. Chainable.
Multiple Instance Methods
Method
Returns
Description
UsingEach<T>(Action<T> use)
IComposition
Executes action for each T capability; silent if none exist. Chainable.
UsingEach<T, TResult>(Func<T, TResult> use)
IReadOnlyList<TResult>
Executes function for each T capability and collects results
UsingAll<T>(Action<IReadOnlyList<T>> use)
IComposition
Executes action with full collection of T capabilities. Chainable.
Executes function with full collection and returns a result
Delegation Mapping
All Using* methods delegate directly to existing IComposition methods:
Using* Method
Delegates To
UsingFirst<T>()
GetRequiredFirst<T>()
UsingFirstOrDefault<T>()
GetFirstOrDefault<T>()
UsingLast<T>()
GetRequiredLast<T>()
UsingLastOrDefault<T>()
GetLastOrDefault<T>()
UsingEach<T>() / UsingAll<T>()
GetAll<T>()
Examples
Single instance usage:
// Required first (throws if missing)composition.UsingFirst<ILogger>(log =>log.Info("started"));// Required first with resultvarcount=composition.UsingFirst<IRepository,int>(repo =>repo.Count());// Optional (silent if missing)composition.UsingFirstOrDefault<ILogger>(log =>log.Info("started"));// Last instance (when order matters)composition.UsingLast<IMiddleware>(m =>m.Execute());
Multiple instance usage:
// Process each capability individuallycomposition.UsingEach<IEventHandler>(handler =>handler.Handle(evt));// Map each to a resultvarcounts=composition.UsingEach<IRepository,int>(repo =>repo.Count());// Returns: [5, 12, 8]// Aggregate operation on collectionvartotal=composition.UsingAll<IRepository,int>(
repos =>repos.Sum(r =>r.Count()));// Returns: 25// Collection operation (chainable)composition.UsingAll<IPlugin>(plugins =>{foreach(varpinplugins)p.Initialize();});
// Use Get* when you need to store/reuse the instancevarlogger=composition.GetRequiredFirst<ILogger>();logger.Info("step 1");logger.Info("step 2");// Use Using* for inline/one-off usagecomposition.UsingFirst<ILogger>(log =>log.Info("one-off message"));// Use Using* for fluent chainingcomposition.UsingFirst<ILogger>(log =>log.Info("starting")).UsingEach<IValidator>(v =>v.Validate());
✅ All Using* methods are thread-safe (they operate on immutable IComposition instances)
✅ User-provided delegates may execute concurrently if the composition is shared across threads
⚠️ User code inside delegates is responsible for its own thread safety
Performance
Zero allocation overhead beyond the user delegate itself
Direct delegation to existing Get* methods (no intermediate objects)
Chainable methods return the same IComposition instance (no copying)
IPrimaryCapability
Marker interface indicating a capability that should be the primary capability for an instance.
Interface Definition
publicinterfaceIPrimaryCapability{}
Rules
Rule
Description
Single Primary
Only one primary capability is allowed per composition
Exception on Duplicate
Attempting to add a second primary capability throws InvalidOperationException
Specialized Retrieval
Primary capabilities have dedicated retrieval methods on IComposition
Example
publicrecordUserPrimaryCapability(stringUserId,stringName):IPrimaryCapability;publicrecordDocumentPrimaryCapability(stringId,stringTitle):IPrimaryCapability;// Use in compositionvarcomposition=scope.Compose(user).Add(newUserPrimaryCapability("user123","John Doe")).Add(newAdminCapability())// Non-primary, OK.Build();
ComposerRegistryApi
Provides access to the composer registry for managing active composers.
Methods
Method
Returns
Description
Has(object subject)
bool
Checks if a composer exists for the subject
Find(object subject)
Composer
Finds the composer for the subject (throws if not found)
GetOrDefault(object subject)
Composer?
Finds the composer or returns null
TryGet(object subject, out Composer composer)
bool
Tries to get the composer for the subject
Example
if(scope.Composers.Has(document)){varcomposer=scope.Composers.Find(document);// Composer is still being built}
CompositionRegistryApi
Provides access to the composition registry for managing built compositions.
Methods
Method
Returns
Description
Has(object subject)
bool
Checks if a composition exists for the subject
Find(object subject)
IComposition
Finds the composition for the subject (throws if not found)
GetOrDefault(object subject)
IComposition?
Finds the composition or returns null
TryGet(object subject, out IComposition composition)
// Add strategies as capabilities, execute in ordervarcomposition=scope.Compose(processor).Add(newValidationStrategy(),order:1).Add(newTransformationStrategy(),order:2).Add(newPersistenceStrategy(),order:3).Build();foreach(varstrategyincomposition.GetAll<IStrategy>()){strategy.Execute();}
// Layer capabilities as decoratorsvarcomposition=scope.Compose(service).Add(newLoggingDecorator(),order:1).Add(newCachingDecorator(),order:2).Add(newValidationDecorator(),order:3).Build();