Binding
A bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. is a rule declared in a Scope that tells Saneject:
- What dependency type should be resolved
- Where candidates come from
- Which injection sitesInjection siteInjected field, property or method. may use the bindingBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. - Optional filters that reject candidates
BindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. are collected from Scope.DeclareBindings() during editor injection, validated, then used to resolve
[Inject] fields, properties and method parameters.
Binding rules
- Every bindingBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. must specify a locator strategyLocator strategyTheFrom...part of a binding that defines where candidates are searched or loaded from. with aFrom...call. - Type matching is strict:
- Specifying an interface is optional; concrete-only bindingsBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. are valid. BindComponent<TConcrete>()andBindAsset<TConcrete>()only matchTConcreteinjection sitesInjection siteInjected field, property or method..BindComponent<TInterface>()only matchesTInterfaceinjection sitesInjection siteInjected field, property or method..BindComponent<TInterface, TConcrete>()andBindAsset<TInterface, TConcrete>only matchTInterfaceinjection sites, with aTConcreteobject that implementsTInterface.
- Specifying an interface is optional; concrete-only bindingsBindingInstruction declared in a
- Single and collection bindingsCollection bindingBinding declared as multiple (
BindComponents/BindAssets/BindMultiple...) that resolves arrays orList<>injection sites. do not mix:- Single bindingsBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. (BindComponent,BindAsset) resolve single fields/properties, parameters. - Collection bindingsCollection bindingBinding declared as multiple (
BindComponents/BindAssets/BindMultiple...) that resolves arrays orList<>injection sites. (BindComponents/BindAssets/BindMultiple...) resolve arrays andList<>.
- Single bindingsBindingInstruction declared in a
- BindingsBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. are local to the declaring scopeScopeMonoBehaviourthat declares bindings for a part of your hierarchy.. If the nearest scopeScopeMonoBehaviourthat declares bindings for a part of your hierarchy. to an injection siteInjection siteInjected field, property or method. has no matching bindingBindingInstruction declared in aScopethat tells Saneject what to resolve, how to inject it, and where to search., Saneject walks up parent scopesScopeMonoBehaviourthat declares bindings for a part of your hierarchy. until it finds one. - Invalid bindingsBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. are excluded from valid resolution and logged.
See Scope for more information
Fluent binding flow
Most bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. follow this general pattern or a combination of these:
BindComponent<IAudioService, AudioManager>()
.ToID("hud") // Optional qualifier that matches [Inject("hud")]
.ToTarget<CombatHud>() // Optional qualifier that matches injection targets of type CombatHud
.ToMember("audioService") // Optional qualifier that matches and methods named "audioService"
.FromTargetSelf() // Required locator strategy that looks for the AudioManager on the transform of the CombatHud
.WhereComponent(c => c.isActiveAndEnabled); // Optional filter that only includes enabled components
This resolves candidates in three phases:
- Match bindingBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. by binding qualifiersBinding qualifierOptional binding restriction declared withToID,ToTarget, orToMember. (if any). - Locate candidates with a
From...method. - Apply
Where...filters (if any).
Binding families
Component bindings
Component bindingsComponent bindingBinding declared with BindComponent... or BindComponents... that resolves Component instances from transforms, hierarchies, scenes, or explicit instances. resolve UnityEngine.Component dependencies from transforms, hierarchy traversal, scene-wide search,
or explicit instances.
protected override void DeclareBindings()
{
// Interface + concrete mapping.
BindComponent<IAudioService, AudioManager>()
.FromScopeSelf();
// Collection binding.
BindComponents<EnemyController>()
.FromScopeDescendants(includeSelf: true)
.WhereComponent(c => c.gameObject.activeInHierarchy);
}
Full component API:
Global component bindings
Global bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. are component bindingsComponent bindingBinding declared with BindComponent... or BindComponents... that resolves Component instances from transforms, hierarchies, scenes, or explicit instances. declared with BindGlobal<TComponent>(). The resolved component is serialized
into the declaring scopeScopeMonoBehaviour that declares bindings for a part of your hierarchy. at editor time and registered in GlobalScope during that scopeScopeMonoBehaviour that declares bindings for a part of your hierarchy.'s Awake().
protected override void DeclareBindings()
{
BindGlobal<AudioManager>()
.FromScopeSelf()
.WhereGameObject(go => go.activeInHierarchy);
}
Global bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. support locator and filter methods, but not binding qualifiersBinding qualifierOptional binding restriction declared with ToID, ToTarget, or ToMember. and not runtime proxyRuntime proxyScriptableObject placeholder asset (RuntimeProxy<TComponent>) injected into interface members at editor time and swapped to the real instance during scope startup. methods.
Full global bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. API:
Asset bindings
Asset bindingsAsset bindingBinding declared with BindAsset... or BindAssets... that resolves UnityEngine.Object assets from project content instead of scene or hierarchy components. resolve UnityEngine.Object assets from Resources, AssetDatabase paths/folders, or explicit
instances.
protected override void DeclareBindings()
{
BindAsset<IGameConfig, GameConfigAsset>()
.ToID("default")
.FromResources("Configs/GameConfig");
BindAssets<AudioClip>()
.FromFolder("Assets/Game/Audio/Sfx")
.Where(clip => clip.name.StartsWith("Enemy_"));
}
Full asset API:
Runtime proxy bindings
Runtime proxy bindingsRuntime proxy bindingComponent binding configured with FromRuntimeProxy() that injects a proxy asset at editor time and swaps it for a real runtime instance during scope initialization. are configured from component bindingsComponent bindingBinding declared with BindComponent... or BindComponents... that resolves Component instances from transforms, hierarchies, scenes, or explicit instances. via FromRuntimeProxy(). They inject a proxy asset at
editor time, then swap to a real runtime instance in the scopeScopeMonoBehaviour that declares bindings for a part of your hierarchy.'s Awake().
Rules:
- Must be
BindComponent<TInterface, TConcrete>(). - Must be single-value (not collection).
- Binding qualifiersBinding qualifierOptional binding restriction declared with
ToID,ToTarget, orToMember. are supported. - Filters are not supported.
protected override void DeclareBindings()
{
BindComponent<ICombatService, CombatService>()
.ToID("combatService")
.FromRuntimeProxy()
.FromGlobalScope();
}
protected override void DeclareBindings()
{
BindComponent<ICombatService, CombatService>()
.FromRuntimeProxy()
.FromComponentOnPrefab(combatServicePrefab, dontDestroyOnLoad: true)
.AsSingleton();
}
Full runtime proxyRuntime proxyScriptableObject placeholder asset (RuntimeProxy<TComponent>) injected into interface members at editor time and swapped to the real instance during scope startup. API:
Binding qualifiers
Binding qualifiersBinding qualifierOptional binding restriction declared with ToID, ToTarget, or ToMember. restrict which injection sitesInjection siteInjected field, property or method. (fields, properties, methods) can be resolved from a bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search..
| Qualifier | Injection site match |
|---|---|
ToID("someId") |
Fields, properties, methods marked with [Inject("someId")] |
ToTarget<TTarget>() |
Fields, properties, methods declared in a TTarget component |
ToMember("someMemberName") |
Fields, properties, methods with name "someMemberName" |
Important behavior:
- Binding qualifiersBinding qualifierOptional binding restriction declared with
ToID,ToTarget, orToMember. are additive, so all specified qualifiers must match. - If a binding qualifierBinding qualifierOptional binding restriction declared with
ToID,ToTarget, orToMember. is not set on the bindingBindingInstruction declared in aScopethat tells Saneject what to resolve, how to inject it, and where to search., the bindingBindingInstruction declared in aScopethat tells Saneject what to resolve, how to inject it, and where to search. matches byTInterfaceorTConcreteonly. - Binding qualifiersBinding qualifierOptional binding restriction declared with
ToID,ToTarget, orToMember. apply to component, asset, and runtime proxy bindingsRuntime proxy bindingComponent binding configured withFromRuntimeProxy()that injects a proxy asset at editor time and swaps it for a real runtime instance during scope initialization.. - Binding qualifiersBinding qualifierOptional binding restriction declared with
ToID,ToTarget, orToMember. do not apply to global bindingsBindingInstruction declared in aScopethat tells Saneject what to resolve, how to inject it, and where to search..
Example:
protected override void DeclareBindings()
{
BindAsset<IGameConfig, GameConfigAsset>()
.ToID("menu")
.ToTarget<MainMenuController>()
.ToMember("config")
.FromResources("Configs/Menu");
}
Binding filters
Binding filtersBinding filterPredicate declared with Where... methods that removes candidates after location and before injection. run after locator search and before final assignment. A candidate (potentially injected dependency) must pass
all filters on the bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search..
Component filter example:
protected override void DeclareBindings()
{
// First component anywhere in the scene, that is active/enabled and is a descendant of a Transform tagged "GameplayRoot".
BindComponent<EnemyController>()
.FromAnywhere()
.WhereComponent(c => c.isActiveAndEnabled)
.WhereAnyAncestor(t => t.CompareTag("GameplayRoot"));
}
Asset filter example:
protected override void DeclareBindings()
{
// All assets in the "Assets/Game/Audio/Music" folder with names starting with "Boss_".
BindAssets<AudioClip>()
.FromFolder("Assets/Game/Audio/Music")
.Where(clip => clip.name.StartsWith("Boss_"));
}
| Binding FamilyBinding familyBinding category with its own resolution behavior and API surface: component, global component, asset, or runtime proxy. | Filter Support |
|---|---|
Component bindingsComponent bindingBinding declared with BindComponent... or BindComponents... that resolves Component instances from transforms, hierarchies, scenes, or explicit instances. |
Yes |
Asset bindingsAsset bindingBinding declared with BindAsset... or BindAssets... that resolves UnityEngine.Object assets from project content instead of scene or hierarchy components. |
Yes |
Global bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. |
Yes (same filter API as component bindingsComponent bindingBinding declared with BindComponent... or BindComponents... that resolves Component instances from transforms, hierarchies, scenes, or explicit instances.). |
Runtime proxy bindingsRuntime proxy bindingComponent binding configured with FromRuntimeProxy() that injects a proxy asset at editor time and swaps it for a real runtime instance during scope initialization. |
No |
If a binding filterBinding filterPredicate declared with Where... methods that removes candidates after location and before injection. throws an exception, Saneject logs a binding filterBinding filterPredicate declared with Where... methods that removes candidates after location and before injection. error for that bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search..
Binding uniqueness
Saneject enforces bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. unique within each Scope. When a bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. is considered duplicate, Saneject logs an error and excludes the duplicate from the injection runInjection runOne execution of the injection pipeline for a chosen selection, context walk filter, and active set of targets..
Duplicate checks use these criteria:
- Same scopeScope
MonoBehaviourthat declares bindings for a part of your hierarchy.. - Same binding familyBinding familyBinding category with its own resolution behavior and API surface: component, global component, asset, or runtime proxy. (
ComponentBindingNode,AssetBindingNode, orGlobalComponentBindingNode). - Same primary type:
TInterfacewhen present.- Otherwise
TConcrete.
- Same single/collection shape.
- Qualifier overlap:
- If both bindingsBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. have no binding qualifiersBinding qualifierOptional binding restriction declared withToID,ToTarget, orToMember. at all, they conflict. - Otherwise, conflict requires full overlap in
ToTarget,ToMember, andToIDsimultaneously.
- If both bindingsBindingInstruction declared in a
Examples:
// Duplicate: same scope, same family, same type, same shape, no qualifiers.
BindComponent<AudioManager>()
.FromScopeSelf();
BindComponent<AudioManager>()
.FromScopeParent(); // Invalid duplicate.
// Distinct: different qualifier sets.
BindAsset<IGameConfig, GameConfigAsset>()
.ToTarget<MainMenuController>()
.ToMember("config")
.ToID("menu")
.FromResources("Configs/Menu");
BindAsset<IGameConfig, GameConfigAsset>()
.ToTarget<GameplayController>()
.ToMember("config")
.ToID("gameplay")
.FromResources("Configs/Gameplay");
Global bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. have an extra rule: only one global bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. per concrete component type is allowed across active
bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. across all scopesScopeMonoBehaviour that declares bindings for a part of your hierarchy.. A second BindGlobal<AudioManager>() is invalid even if declared in another scopeScopeMonoBehaviour that declares bindings for a part of your hierarchy..
Binding validation
While the fluent API prevents most invalid bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search., it's still possible to create invalid bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. that will compile. However, the injection runInjection runOne execution of the injection pipeline for a chosen selection, context walk filter, and active set of targets. has a validation step that catches invalid bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search., excludes them from the run and logs them as errors.
Current validation checks include:
- Duplicate bindingBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. in the same scopeScopeMonoBehaviourthat declares bindings for a part of your hierarchy.. - Duplicate global bindingBindingInstruction declared in a
Scopethat tells Saneject what to resolve, how to inject it, and where to search. by concrete type. - Runtime proxy bindingRuntime proxy bindingComponent binding configured with
FromRuntimeProxy()that injects a proxy asset at editor time and swaps it for a real runtime instance during scope initialization. constraints:- Interface type required.
- Concrete type required.
- Collection mode not allowed.
- Component bindingComponent bindingBinding declared with
BindComponent...orBindComponents...that resolvesComponentinstances from transforms, hierarchies, scenes, or explicit instances. concrete type must derive fromUnityEngine.Component. - Asset bindingAsset bindingBinding declared with
BindAsset...orBindAssets...that resolvesUnityEngine.Objectassets from project content instead of scene or hierarchy components. concrete type must not derive fromUnityEngine.Component. - Interface type must actually be an interface.
- Concrete type must implement the declared interface.
- Locator strategyLocator strategyThe
From...part of a binding that defines where candidates are searched or loaded from. must be set.
Examples of invalid but compilable bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search.:
// Invalid: no locator strategy specified.
BindAsset<GameConfigAsset>();
// Invalid: runtime proxy bindings cannot be collection bindings.
BindComponents<ICombatService, CombatService>()
.FromRuntimeProxy();
Validation runs before dependency resolution, so invalid bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. are never used to satisfy [Inject] members.