Table of Contents

Context

A contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. is Saneject's way of saying "this object belongs to this serialized boundary".

Saneject uses contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. during editor injection to answer two questions:

  • Which transforms participate in the injection walk?
  • Which potential dependency candidatesDependency candidateObject considered during resolution before qualifiers, filters, and assignment determine whether it becomes the final injected dependency. can be injected in this component?

Context types

For GameObject hierarchies, Saneject uses these contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. types:

  • Scene object: a regular object in a scene.
  • Prefab instance: a prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. in a scene or nested inside another prefab.
  • Prefab asset: the prefab assetPrefab assetReusable prefab definition in the Project window. in the Project window.

Context equalityContext equalityRule for determining whether two objects are in the same context. Equality is instance-specific and based on context identity, not just context type. is instance-specific, not type-based. Saneject assigns a contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. ID and uses that ID to compare context equalityContext equalityRule for determining whether two objects are in the same context. Equality is instance-specific and based on context identity, not just context type.. The same rule applies to scenes, prefab instancesPrefab instanceInstantiated prefab placed in a scene or nested inside another prefab., and prefab assetsPrefab assetReusable prefab definition in the Project window..

Example:

  • Scene A and Scene B are different contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..
  • Prefab instancesPrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. of the same prefab assetPrefab assetReusable prefab definition in the Project window. are different contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..
  • Each prefab assetPrefab assetReusable prefab definition in the Project window. is its own contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..

Each contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. also belongs to a containing serialized boundary:

  • Scene objectsScene objectNon-prefab GameObject in a scene. and prefab instancesPrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. placed in a scene belong to that scene.
  • Prefab assetPrefab assetReusable prefab definition in the Project window. objects and nested prefab instancesPrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. inside a prefab assetPrefab assetReusable prefab definition in the Project window. belong to that prefab assetPrefab assetReusable prefab definition in the Project window..

This matters because with context isolationContext isolationProject setting (UseContextIsolation) that controls whether dependency resolution can cross context boundaries. disabled, Saneject still does not treat every contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. as compatible with every other one. It only relaxes boundaries inside the same containing scene or prefab assetPrefab assetReusable prefab definition in the Project window..

Why contexts exist

Unity already enforces some serialization boundariesSerialization boundaryBoundary that determines which objects belong to the same serialized context for resolution and injection.. For example, scene objectsScene objectNon-prefab GameObject in a scene. cannot serialize direct references to prefab assetPrefab assetReusable prefab definition in the Project window. objects, and vice versa.

However, edit-time injection can still create dependencies across boundaries where Unity technically allows references, like between a scene objectScene objectNon-prefab GameObject in a scene. and prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. within the same scene. That can make a prefab depend on the scene where it was authored, making it less modular and portable to other contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..

Saneject addresses this with two controls:

  • Context isolation: controls whether dependency resolution can cross contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..
  • Context filtering: controls which contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. are included in a specific injection runInjection runOne execution of the injection pipeline for a chosen selection, context walk filter, and active set of targets..

Context isolation

Context isolation is a project settingProject settingsSaneject settings shared at project scope, stored in ProjectSettings/Saneject/ProjectSettings.json and available from Saneject/Settings -> Project Settings..

  • UI path: Saneject/Settings/Project Settings/Use Context Isolation
  • File path: {ProjectRoot}/ProjectSettings/Saneject/ProjectSettings.json

Because it is in ProjectSettings, teams can version control and share the same behavior. It is important that the entire project uses the same isolation setting so injection stays deterministic for everyone.

What isolation changes

When Saneject resolves an [Inject] member, there are two relevant steps:

  1. Find a matching bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. by walking scopesScopeMonoBehaviour that declares bindings for a part of your hierarchy. upward.
  2. Locate dependency candidatesDependency candidateObject considered during resolution before qualifiers, filters, and assignment determine whether it becomes the final injected dependency. from the chosen bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search..

With isolation enabled:

  • Step 1 only considers scopesScopeMonoBehaviour that declares bindings for a part of your hierarchy. in the same contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. as the injection targetInjection targetComponent with injected fields, properties or methods. component.
  • Step 2 rejects dependency candidatesDependency candidateObject considered during resolution before qualifiers, filters, and assignment determine whether it becomes the final injected dependency. from other contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..

With isolation disabled:

  • Step 1 can walk across scene objectScene objectNon-prefab GameObject in a scene. and prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. boundaries inside the same containing scene or prefab assetPrefab assetReusable prefab definition in the Project window..
  • Step 2 can also accept dependency candidatesDependency candidateObject considered during resolution before qualifiers, filters, and assignment determine whether it becomes the final injected dependency. across those boundaries.

Values resolved through asset bindingsAsset bindingBinding declared with BindAsset... or BindAssets... that resolves UnityEngine.Object assets from project content instead of scene or hierarchy components. are a separate case. They are treated as contextless for resolution purposes, so they are not filtered by scene or prefab contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. boundaries in the same way hierarchy-bound candidates are.

Practical effect

  • UseContextIsolation = true: Strict boundaries. A component can only get injected into other components from its own contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility., e.g., a component on a prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. cannot be injected into a component on a scene objectScene objectNon-prefab GameObject in a scene..
  • UseContextIsolation = false: Relaxed boundaries inside the same containing scene or prefab assetPrefab assetReusable prefab definition in the Project window.. Components can be injected across contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. within that boundary, e.g., a component on a prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. can be injected into a component on a scene objectScene objectNon-prefab GameObject in a scene. in the same scene.

Context filtering

Context filtering decides which injection targetsInjection targetComponent with injected fields, properties or methods. are included in an injection runInjection runOne execution of the injection pipeline for a chosen selection, context walk filter, and active set of targets., meaning which components are processed for injection.

Saneject builds the injection graphInjection graphHierarchy model built from selected root hierarchies. It contains transform, component, scope, binding, and injection-member information used by the edit-time pipeline. first, then applies the selected ContextWalkFilter. Only the filtered transforms become active, and only components under those transforms are processed.

What filtering does not do: it does not change context isolationContext isolationProject setting (UseContextIsolation) that controls whether dependency resolution can cross context boundaries. rules, and it does not directly filter dependency candidatesDependency candidateObject considered during resolution before qualifiers, filters, and assignment determine whether it becomes the final injected dependency. returned by an active bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search..

So if an active bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. searches into another contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility., those candidates can still be found. Whether they are accepted is still decided by UseContextIsolation.

Example: run with SceneObjects filter, and a scene Scope bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. uses FromDescendants. If that hierarchy contains a prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. child, the bindingBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. can still find components on that prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab..

  • UseContextIsolation = false: those cross-context candidates can be injected.
  • UseContextIsolation = true: those cross-context candidates are rejected.

Why use filters

Filters are most useful as a focused debugging and iteration tool in large hierarchies. For example, in a large scene, SceneObjects lets you validate scene-object wiring without processing prefab instancesPrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. in the same pass.

A common workflow is:

  • Use filters selectively while developing or debugging.
  • Run a full injection pass (AllContexts or normal full scene/prefab injection) before final validation.

Filter options

  • AllContexts: process all transform nodes in the graph.
  • SameContextsAsSelection: process only nodes that match the selected object contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..
  • SceneObjects: process only scene objectScene objectNon-prefab GameObject in a scene. contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..
  • PrefabAssetObjects: process only prefab assetPrefab assetReusable prefab definition in the Project window. contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..
  • PrefabInstances: process only prefab instancePrefab instanceInstantiated prefab placed in a scene or nested inside another prefab. contextsContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility..

Where filters are used

You can pick run filters from:

  • Injection context menuInjection context menuEditor command under Saneject/Inject Scene/..., Saneject/Inject Selected Scene Hierarchies/..., Saneject/Inject Prefab Asset/..., or the matching GameObject/Saneject/... paths that start an injection run with a selected target and ContextWalkFilter. items.
  • Batch Inject Selected Assets menu items under Assets/Saneject/Batch Inject Selected Assets/... and Saneject/Batch Inject Selected Assets/....
  • The ContextWalkFilter dropdown in the Batch InjectorBatch InjectorEditor window for preparing and running batch injection with per-asset enable state, status, and ContextWalkFilter. window for supported scene and prefab assetPrefab assetReusable prefab definition in the Project window. runs.

Isolation vs filtering

These features solve different problems:

  • Context filteringContext filteringInjection-run prefilter that decides which transforms and injection targets are active for a run. decides what enters the run.
  • Context isolationContext isolationProject setting (UseContextIsolation) that controls whether dependency resolution can cross context boundaries. decides what gets injected where inside that run.

So you can run AllContexts and still keep strict boundaries by enabling context isolationContext isolationProject setting (UseContextIsolation) that controls whether dependency resolution can cross context boundaries.. Or you can run a narrow filter and still allow cross-context resolution by disabling context isolationContext isolationProject setting (UseContextIsolation) that controls whether dependency resolution can cross context boundaries..

Pipeline summary

At a high level, Saneject applies contextContextSerialization boundary Saneject uses during injection to decide scope traversal and candidate eligibility. rules in this order:

  1. Build the injection graphInjection graphHierarchy model built from selected root hierarchies. It contains transform, component, scope, binding, and injection-member information used by the edit-time pipeline. from the selected start roots.
  2. Apply ContextWalkFilter to select active transforms.
  3. Build active components, scopesScopeMonoBehaviour that declares bindings for a part of your hierarchy., and bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. from those transforms.
  4. Resolve bindingsBindingInstruction declared in a Scope that tells Saneject what to resolve, how to inject it, and where to search. and dependency candidatesDependency candidateObject considered during resolution before qualifiers, filters, and assignment determine whether it becomes the final injected dependency..
  5. Apply context isolationContext isolationProject setting (UseContextIsolation) that controls whether dependency resolution can cross context boundaries. rules while resolving.

Cross-context dependencies

If a dependency must cross a hard boundary (for example scene to prefab assetPrefab assetReusable prefab definition in the Project window.), use a runtime proxyRuntime proxyScriptableObject placeholder asset (RuntimeProxy<TComponent>) injected into interface members at editor time and swapped to the real instance during scope startup.. That is the intended pattern for cross-context wiring.

See Runtime proxy for details.

Visual examples

flowchart TB
  subgraph Iso["Context isolation"]
    EM["EnemyManager<br/>(scene object)"] -->|"Injected into GameManager"| GM["GameManager<br/>(scene object)"]
    P["Player<br/>(prefab instance)"] --> Q{"UseContextIsolation?"}
    Q -->|"true"| B["Not injected<br/>into GameManager"]
    Q -->|"false"| A["Injected<br/>into GameManager"]
    A --> GM
    B -.-> GM
  end
flowchart LR
  subgraph Fil["Context filtering"]
    R["Scene injection run"] --> F{"ContextFilter"}
    
    F --> A["AllContexts"]
    F --> S["SceneObjects"]
    F --> P["PrefabInstances"]
    
    A -->|"Processed"| AGM["GameManager<br/>(scene object)"]
    A -->|"Processed"| AP["Player<br/>(prefab instance)"]
    
    S -->|"Processed"| SGM["GameManager<br/>(scene object)"]
    S -.->|"Not processed"| SP["Player<br/>(prefab instance)"]
    
    P -.->|"Not processed"| PGM["GameManager<br/>(scene object)"]
    P -->|"Processed"| PP["Player<br/>(prefab instance)"]
  end