All Projects

Saneject

July, 2025

Saneject is an editor-time dependency injection framework for Unity, providing deterministic serialized reference injection, clean classes, and minimal runtime overhead. Features Roslyn-powered interface serialization, scoped bindings, and intuitive inspector integration.

Saneject logo showcasing clean, minimalistic style, representing deterministic injection.

Introduction

  • Overview: Saneject is an editor-time dependency injection (DI) framework for Unity that simplifies serialized field injections, minimizes runtime overhead, and provides clear inspector integration. Designed to bridge the gap between manual wiring and heavy runtime DI frameworks, Saneject leverages Roslyn source generators and intuitive editor tools to streamline dependency management.

  • Motivation: As Unity projects scale, runtime DI solutions like Zenject become resource-intensive, introducing complexity and runtime overhead. Manual dependency wiring, meanwhile, quickly becomes unmanageable and error-prone. I created Saneject to provide deterministic, transparent, and performant dependency injection, combining the best aspects of both approaches.

Key Features

  • Editor-Time Injection: Dependencies resolved deterministically within the Unity Editor, serialized directly into fields without runtime overhead.
  • Roslyn Interface Serialization: Interfaces serialized directly into inspector-visible fields via Roslyn-generated backing fields, removing Unity’s inherent interface serialization limitation.
  • Scoped Binding API: Fluent API for defining component and object bindings within specific hierarchy contexts or globally, ensuring clarity and encapsulation.
  • Cross-Scene & Prefab References: Automatically generated proxy objects facilitate referencing between scenes and prefabs, overcoming Unity’s serialization restrictions.
  • Inspector UX: Injected fields grayed out or hidden, clear labels, contextual help boxes, and intuitive user interactions integrated directly into the Unity inspector.
  • Global Scope Management: Promote dependencies to global singletons available across scenes, efficiently managed at runtime.
  • Performance Optimization: Zero runtime reflection or container overhead. Proxies resolve once, cache instances, and provide near-zero-cost lookups.
  • Fail-Fast Validation: Immediate detection of conflicting, missing, or invalid bindings during the injection process, preventing runtime issues.
  • Unified Scope Handling: Single Scope component handles injections for both scenes and prefabs, automatically detecting context to streamline usage.
  • User Customization: User settings panel allows toggling injection prompts, inspector visibility, and logging behavior for enhanced usability.

Key Challenges & Solutions

1. Interface Serialization with Roslyn

  • Challenge: Unity inherently cannot serialize interfaces, limiting inspector functionality and complicating DI workflows.
  • Solution: Implemented Roslyn source generators that create partial classes with hidden backing Object fields. These fields enable direct serialization and deserialization of interfaces, providing transparent and type-safe inspector integration.

2. Cross-Scene and Prefab Dependency Referencing

  • Challenge: Unity’s serialization system doesn’t allow direct scene-to-prefab or cross-scene object references.
  • Solution: Built InterfaceProxyObject<T>, a Roslyn-generated ScriptableObject that forwards calls to actual scene instances at runtime. Proxies cache resolved instances for minimal overhead, enabling previously impossible referencing scenarios.

3. Unified Scope Management Across Scenes and Prefabs

  • Challenge: Traditional DI frameworks use separate approaches for scenes and prefabs, creating inconsistent workflows.
  • Solution: Created a single Scope component that automatically detects whether it’s on a scene or prefab, managing injections appropriately. Prefabs are self-contained, with scene injections skipping prefab-bound dependencies.

4. Transparent Inspector Integration

  • Challenge: Runtime DI solutions often obscure dependency wiring, complicating debugging and reducing clarity for designers.
  • Solution: Implemented an enhanced inspector that clearly indicates injected fields as grayed-out or hidden, provides detailed contextual help boxes, and ensures fields appear directly beneath their respective interfaces, improving transparency and maintainability.

5. Runtime Performance and Reflection Overhead

  • Challenge: Runtime DI containers commonly introduce significant reflection overhead and complexity at startup, negatively impacting performance.
  • Solution: Shifted all dependency resolution to editor-time, fully serializing references. At runtime, Saneject uses only cached serialized data, ensuring negligible performance impact with zero reflection.

6. Flexible Binding API

  • Challenge: Developers require expressive and precise control over dependency scopes, locations, and filtering conditions.
  • Solution: Designed a fluent binding API supporting hierarchical, targeted, and filtered resolutions (by tags, layers, naming conventions). Binding methods clearly communicate dependency locations, ensuring precise and intuitive wiring.

7. Robust Validation and Error Handling

  • Challenge: Silent binding failures or invalid configurations can cause hard-to-debug runtime issues.
  • Solution: Developed fail-fast validation logic that immediately flags missing, conflicting, or invalid bindings during editor injection passes, providing developers instant feedback and ensuring robust configurations.

Future Development

Saneject is actively evolving, with planned enhancements including:

  • Circular Dependency Detection: Implement automated detection and resolution guidance for circular references to simplify debugging.
  • Unity Package Manager (UPM) Integration: Official support via UPM for streamlined installation and management.
  • Multi-Binding Support: Injection of collections (e.g., IEnumerable<T>), enhancing flexibility for batch injections.
  • Improved Proxy Generation Workflow: Enhanced UX for generating interface proxies, minimizing friction and improving reliability.
  • Expanded Platform Support: Comprehensive testing across iOS, WebGL, and console platforms to ensure consistent performance.
  • Enhanced Debugging Tools: Additional tooling and logging improvements for deep diagnostics and streamlined debugging workflows.

Conclusion

Saneject provides a clean, performant, and intuitive solution for dependency injection in Unity projects, merging the clarity of manual wiring with the power of structured DI. With editor-time resolution, Roslyn-powered serialization, and polished inspector integration, Saneject ensures developers can focus on building robust and maintainable applications without runtime overhead.

For more details, visit the GitHub repository.

Hire a Senior Unity Developer for XR, Games & Apps

9+ years experience building scalable, performant Unity solutions, XR, games, enterprise apps, prototypes, custom tools, and complex systems.

Available for freelance, consulting, or full project development. I reply within 1 business day.

Get in Touch