{"id":18788717,"url":"https://github.com/pereviader/manualdi","last_synced_at":"2026-03-01T21:26:05.609Z","repository":{"id":43395592,"uuid":"330033897","full_name":"PereViader/ManualDi","owner":"PereViader","description":"Fast and extensible C# dependency injection library without reflection. Works seamlessly in both Unity3d and plain C# projects","archived":false,"fork":false,"pushed_at":"2026-03-01T19:32:10.000Z","size":715,"stargazers_count":64,"open_issues_count":3,"forks_count":3,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-01T19:49:18.267Z","etag":null,"topics":["csharp","dependency-injection","dependency-injection-container","dotnet","ioc","ioc-container","unity3d","unity3d-plugin"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PereViader.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-01-15T22:14:29.000Z","updated_at":"2026-03-01T19:32:14.000Z","dependencies_parsed_at":"2024-08-10T20:58:36.299Z","dependency_job_id":"7f5e21db-135c-4398-9601-e67e80f44a99","html_url":"https://github.com/PereViader/ManualDi","commit_stats":null,"previous_names":["pereviader/manualdi","pereviader/manualdi.main"],"tags_count":66,"template":false,"template_full_name":null,"purl":"pkg:github/PereViader/ManualDi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PereViader%2FManualDi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PereViader%2FManualDi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PereViader%2FManualDi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PereViader%2FManualDi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PereViader","download_url":"https://codeload.github.com/PereViader/ManualDi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PereViader%2FManualDi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29984718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-01T21:06:37.093Z","status":"ssl_error","status_checked_at":"2026-03-01T21:05:45.052Z","response_time":124,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["csharp","dependency-injection","dependency-injection-container","dotnet","ioc","ioc-container","unity3d","unity3d-plugin"],"created_at":"2024-11-07T21:05:39.938Z","updated_at":"2026-03-01T21:26:05.602Z","avatar_url":"https://github.com/PereViader.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Test and publish](https://github.com/PereViader/ManualDi/actions/workflows/TestAndPublish.yml/badge.svg)](https://github.com/PereViader/ManualDi/actions/workflows/TestAndPublish.yml) [![Unity version 2022.3.29](https://img.shields.io/badge/Unity-2022.3.29-57b9d3.svg?style=flat\u0026logo=unity)](https://github.com/PereViader/ManualDi.Unity3d) [![OpenUPM ManualDi.Sync](https://img.shields.io/npm/v/com.pereviader.manualdi.sync.unity3d?label=openupm%20sync\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.pereviader.manualdi.sync.unity3d/) [![OpenUPM ManualDi.Async](https://img.shields.io/npm/v/com.pereviader.manualdi.async.unity3d?label=openupm%20async\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.pereviader.manualdi.async.unity3d/) [![NuGet ManualDi.Sync](https://img.shields.io/nuget/v/ManualDi.Sync?label=nuget%20sync)](https://www.nuget.org/packages/ManualDi.Sync) [![NuGet ManualDi.Async](https://img.shields.io/nuget/v/ManualDi.Async?label=nuget%20async)](https://www.nuget.org/packages/ManualDi.Async) [![Release](https://img.shields.io/github/release/PereViader/ManualDi.svg?label=github%20release)](https://github.com/PereViader/ManualDi/releases/latest)\n\nWelcome to ManualDi – a fast and extensible C# dependency injection library\n- Unified API to create, inject, initialize and startup the application.\n- Focuses on reducing boilerplate\n- Synchronous and asynchronous library variants.\n- Supercharge the container with tailored extensions for your application.\n- Source generation, no reflection - Faster and more memory efficient than most other dependency injection containers.\n- Seamless Unity3D game engine integration.\n\n# Benchmark and Comparison\n\nBenchmarkDotNet [Sync](https://github.com/PereViader/ManualDi/blob/main/ManualDi.Sync/ManualDi.Sync.Benchmark/Benchmark.cs) and [Async](https://github.com/PereViader/ManualDi/blob/main/ManualDi.Async/ManualDi.Async.Benchmark/Benchmark.cs) benchmarks between Microsoft and ManualDi\n\n```\n| Method         | Mean [ns] | Error [ns]  | StdDev [ns] | Gen0   | Gen1   | Allocated [KB] |\n|------------    |----------:|------------:|------------:|-------:|-------:|---------------:|\n| NoContainer    |  2.598 ns |   0.0811 ns |   0.1137 ns | 0.0005 | 0.0000 |        0.02 KB |\n| ManualDi.Sync  |  4,047 ns |  76.3106 ns |  74.9472 ns | 0.2747 | 0.0076 |       13.77 KB |\n| ManualDi.Async |  6,787 ns |  91.7127 ns |  85.7881 ns | 0.3128 | 0.0153 |        15.4 KB |\n| MicrosoftDi    | 40,357 ns | 796.7055 ns |    1,142 ns | 2.5024 | 0.6714 |      122.87 KB |\n```\n\nUnity3d [Sync](https://github.com/PereViader/ManualDi/blob/main/ManualDi.Sync.Unity3d/Assets/ManualDi.Sync.Unity3d/Tests/Benchmark.cs) and [Async](https://github.com/PereViader/ManualDi/blob/main/ManualDi.Async.Unity3d/Assets/ManualDi.Async.Unity3d/Tests/Benchmark.cs) benchmarks between [Zenject](https://github.com/modesttree/Zenject), [VContainer](https://github.com/hadashiA/VContainer), [Reflex](https://github.com/gustavopsantos/Reflex) and ManualDi\n\n\n![Unity3d-Container-Benchmark](https://github.com/user-attachments/assets/1d697925-0a6a-480d-83c5-703f9706b80b)\n- Zenject performance measured with Reflection Baking enabled\n- VContainer performance measured with source generation enabled\n- Performance measured on a windows standalone build\n\n|                                 |ManualDi.Sync|ManualDi.Async|Reflex|VContainer|Zenject|\n|---------------------------------|:-------------------------:|:--------------:|:--------------------:|:-------------------------------:|:-------------------------------:|\n| Lifetimes                       |Single\u003cbr/\u003eTransient *(1)|Single *(2)|Single\u003cbr/\u003eTransient|Single\u003cbr/\u003eTransient\u003cbr/\u003eScoped|Single\u003cbr/\u003eTransient\u003cbr/\u003eScoped|\n| Runtime (lower is better)       |0.11|0.16|0.15|0.36|1|\n| Memory (lower is better)        |0.12|0.14|0.21|0.59|1|\n| Object Injection                |✅|✅|✅|✅|✅|\n| Scopes                          |✅|✅|✅|✅|✅|\n| Resolution During Installation  |✅|✅|✅|❌|❌|\n| Object Initialization           |✅|✅|❌|❌|❌|\n| Object Lifecycle Hooks          |✅|✅|❌|❌|❌|\n| Startup Hooks                   |✅|✅|❌|❌|❌|\n| Lazy                            |❌ *(3)|❌ *(3)|✅|❌|✅|\n| Avoids Reflection               |✅|✅|❌ *(4)|❌ *(4)|❌ *(4)|\n\n*This table is still WIP, please open a discussion if you have any suggestion.\n\n- (1) ManualDi.Sync does not have Scoped scope.\n  - Scoped can be achived by setting up the binding on the child container. That child container is effectively another scope.\n\n- (2) ManualDi.Async only works with Single scope.\n  - Transient can be achived by setting up a factory class. The factory class can be used to create the instance at runtime.\n  - Scoped can be achived by setting up the binding on the child container. That child container is effectively another scope.\n\n- (3) ManualDi does not support lazy binding. All bound instances will get created and injected.\n  - Lazy bindings are usually a source of bugs and confusion.\n\n- (4) Reflex, VContainer, Zenject don't avoid Reflection by default but.\n  - They do work on IL2CPP (some have some caveats).\n  - Reflex only uses reflection on a few places.\n  - VContainer has an optional Source Generator that can replace the reflection based execution.\n\n# Installation\n\n- Plain C#: Install it using nuget (netstandard2.1) \n  - Sync: https://www.nuget.org/packages/ManualDi.Sync/\n  - Async: https://www.nuget.org/packages/ManualDi.Async/\n\n- Unity3d [2022.3.29](https://github.com/PereViader/ManualDi/issues/25) or later \n    - (Recommended) OpenUPM [(instructions)](https://openupm.com/docs/getting-started.html#google_vignette)\n        - Sync: https://openupm.com/packages/com.pereviader.manualdi.sync.unity3d/\n        - Async: https://openupm.com/packages/com.pereviader.manualdi.async.unity3d/\n    - Directly from git [(instructions)](https://docs.unity3d.com/6000.1/Documentation/Manual/upm-ui-giturl.html)\n        - Git URL: https://github.com/PereViader/ManualDi.Unity3d.git\n\nNote: \\* [.Net Compact Framework](https://es.wikipedia.org/wiki/.NET_Compact_Framework) is [not compatible](https://learn.microsoft.com/en-us/dotnet/api/system.type.typehandle?view=net-8.0#system-type-typehandle) because of an [optimization](https://github.com/PereViader/ManualDi/commit/d7965d1b77b905084bb1fdf8fdad7c4f53f63fb5)\n\nNote: Source generation will only happen in csproj that are linked both with the source generator and the library.\n- In a regular C# project, this requires referencing the library on the csproj as a nuget package\n- In a Unity3d project, this requires adding the library to the project through the Package Manager and then referencing ManualDi on each assembly definition where you want to use it\n\nNote: Source generator will never run on 3rd party libraries and System classes because they won't reference the generator.\n\nNote: Source generation is opt-in. You must decorate your classes with `[ManualDi]` attribute for the generator to process them. This ensures better performance and avoids generating code for unrelated classes.\n\nLimitation of the source generator:\n- Does not run for partial classes defined across multiple declarations. It will only operate on partial classes that are declared once.\n- Does not run for classes that use the `required` keyword\n\n# Container Lifecycle\n\n- Binding Phase: Container binding configuration is defined \n- Building Phase: Binding configuration is used to create the object graph\n- Startup Phase: Startup callbacks are run.\n- Alive Phase: Container is returned to the user and it can be kept until it is no longer necessary. \n- Disposal Phase: The container and its resources are released.\n\nIn the section below we will add two examples to see an example of the lifecycle\n\n- Creating the builder and installing the bindings is where the binding phase happens\n- Within the execution of the `Build` method both the Building and Startup phase will happen\n    - The container and object graph is be created\n    - Startup callbacks of the application are invoked\n- Notice that the container variable is `using` or `await using` in order to ensure that the container is disposed of when it is no longer needed.\n\n## ManualDi.Sync sample\n\n```csharp\nusing DiContainer diContainer = new DiContainerBindings()\n    .Install(b =\u003e {\n        // Setup the instances involved in the object graph\n        // The order of instantiation, injection and subsequent initialization is the reverse of the dependency graph\n        // A consistent and reliable order of execution prevents issues that happen when instances are used when not yet properly initialized\n        b.Bind\u003cSomeClass\u003e().Default().FromConstructor();\n        b.Bind\u003cIOtherClass, OtherClass\u003e().Default().FromConstructor();\n        b.Bind\u003cStartup\u003e().Default().FromConstructor();\n\n        // Instruct the container the Startup logic to run once all dependencies created and initialized.\n        b.QueueStartup\u003cStartup\u003e(static startup =\u003e startup.Execute());\n    })\n    .Build();\n\npublic interface IOtherClass { }\n\n[ManualDi]\npublic class OtherClass : IOtherClass, IDisposable\n{\n    // Runs first because the class does not depend on anything else\n    public void Initialize() =\u003e Console.WriteLine(\"OtherClass.Initialize\");\n\n    // Runs last because the class does not depend on anything else\n    public void Dispose() =\u003e Console.WriteLine(\"SomeClass.Dispose\");\n}\n\n[ManualDi]\npublic class SomeClass(IOtherClass otherClass) : IDisposable\n{\n    // SomeClass.Initialize runs after OtherClass.Initialize\n    public void Initialize() =\u003e Console.WriteLine(\"SomeClass.Initialize\");\n\n    // SomeClass.Dispose runs before OtherClass.Dispose\n    public void Dispose() =\u003e Console.WriteLine(\"SomeClass.Dispose\");\n}\n\n[ManualDi]\npublic class Startup(SomeClass someClass)\n{\n    private IOtherClass otherClass;\n\n    //Inject runs after the constructor\n    public void Inject(IOtherClass otherClass) =\u003e this.otherClass = otherClass;\n\n    // Runs after SomeClass.Initialize and OtherClass.InitializeAsync\n    public void Execute() =\u003e Console.WriteLine(\"Startup.Execute\");\n}\n```\n\nSample output\n\n```\nOtherClass.Initialize\nSomeClass.Initialize\nStartup.Execute\nSomeClass.Dispose\nOtherClass.Dispose\n```\n\n## ManualDi.Async sample\n\n```csharp\nawait using DiContainer diContainer = await new DiContainerBindings()\n    .Install(b =\u003e {\n        // Setup the instances involved in the object graph\n        // The order of instantiation, injection and subsequent initialization is the reverse of the dependency graph\n        // A consistent and reliable order of execution prevents issues that happen when instances are used when not yet properly initialized\n        b.Bind\u003cSomeClass\u003e().Default().FromConstructor();\n        b.Bind\u003cIOtherClass, OtherClass\u003e().Default().FromConstructor();\n        b.Bind\u003cStartup\u003e().Default().FromConstructor();\n\n        // Instruct the container the Startup logic to run once all dependencies created and initialized.\n        b.QueueStartup\u003cStartup\u003e(static async (startup, ct) =\u003e startup.Execute(ct));\n    })\n    .Build(CancellationToken.None);\n\npublic interface IOtherClass { }\n\n[ManualDi]\npublic class OtherClass : IOtherClass, IAsyncDisposable\n{\n    // Runs first because the class does not depend on anything else\n    public async Task InitializeAsync(CancellationToken ct) =\u003e Console.WriteLine(\"OtherClass.InitializeAsync\");\n\n    // Runs last because the class does not depend on anything else\n    public async ValueTask DisposeAsync() =\u003e Console.WriteLine(\"OtherClass.DisposeAsync\");\n}\n\n[ManualDi]\npublic class SomeClass(IOtherClass otherClass) : IDisposable\n{\n    // SomeClass.Initialize runs after OtherClass.InitializeAsync\n    public void Initialize() =\u003e Console.WriteLine(\"SomeClass.Initialize\");\n\n    // SomeClass.Dispose runs before OtherClass.DisposeAsync\n    public void Dispose() =\u003e Console.WriteLine(\"SomeClass.Dispose\");\n}\n\n[ManualDi]\npublic class Startup(SomeClass someClass)\n{\n    private IOtherClass otherClass;\n\n    //Inject runs after the constructor\n    public void Inject(IOtherClass otherClass) =\u003ethis.otherClass = otherClass;\n\n    // Runs after SomeClass.Initialize and OtherClass.InitializeAsync\n    public async Task Execute(CancellationToken ct) =\u003e Console.WriteLine(\"Startup.Execute\");\n}\n```\n\nSample output\n\n```\nOtherClass.InitializeAsync\nSomeClass.Initialize\nStartup.Execute\nSomeClass.Dispose\nOtherClass.DisposeAsync\n```\n\n# Why use Dependency Injection\n\n## General\n\n- Fail Faster: The application can only start when the whole object graph is correct. Runtime failures on the object graph are much harder to implement into the codebase.\n\n- Decouples Components: Classes do not create the objects they depend on. Instead, these dependencies are \"injected\" from an external source. This decoupling means that components are not tightly bound to specific implementations of their dependencies.\n\n- Explicit Dependencies: With constructor/method injection, a class's dependencies are listed right in its signature. This makes the code self-documenting. You can immediately see what a class needs to function, making it far easier for new developers to understand the architecture and for you to reason about your own code.\n\n- Enhances Flexibility: Because components are not tied to concrete classes but rather to abstractions, you can easily swap out implementations of a dependency without altering the dependent class. This easily lets you implement A/B tests and the implementation of a whole system without the consumers noticing as long as the interface contract is maintained.\n\n- Encourages Reusable Components: By removing direct dependencies on other concrete classes, components become more self-contained and can be more easily reused across different parts of an application or even in different projects.\n\n- Easier Refactoring: With loosely coupled components, refactoring or updating a part of the application is less likely to have a cascading effect on other parts of the codebase. Changes to a dependency's implementation details do not require changes in the classes that consume it, as long as the contract (interface) remains the same.\n\n- Effortless Testing: When testing a component that is implemented with dependency injection in mind, you can inject mock/stub/fake/... implementations. This allows you to isolate the unit of code you are testing from the rest of the system, leading to more reliable and focused tests.\n\n## Unity3d\n\n- Supercharge Serialized objects: Unity has a great system to serialize data on UnityEngine.Objects. Adding a DiContainer on top means that you can easily connect that data with your code-driven implementation.\n\n- Cross-Scene Dependencies: Object dependencies are tricky to interconnect when multiple dynamically scenes and/or prefabs are loaded. ManualDi in Unity3d facilitate interconnecting those with minimal boilerplate.\n\n# Quick concepts\n\nLet's briefly discuss a few concepts from the library to get a high level overview\n\n- The container is created using a builder `DiContainerBindings`.\n- Container configuration is setup through a fluent API available through `Bind` methods.\n- Speed is achived via source generated, reflection-free, `Default` and `FromConstructor` methods.\n- The `FromConstructor` method instructs the Binding to use `TConcrete`'s constructor, resolving parameters from the container.\n- There are more construction methods other than `FromConstructor`.\n- Method injection is accomplished by adding an `Inject` method to your Types.\n- Instance initialization is accomplished by adding an `Initialize` or `InitializeAsync`** method.\n- The `Default` method configures the `Binding` to use `TConcrete`'s `Inject`, `Initialize` and `InitializeAsync`** methods\n- Instances are created injected and initialized in inverse dependency order.\n- Once the object graph is created and initialized, `QueueStartup` callbacks are invoked\n- Once all Startup callbacks are run, the container is returned to the user\n- When the application wants to dispose of the object graph dangling from the container, it can do it by disposing of the container\n\n# Binding\n\nThe container configuration is done through a fluent API available on `DiContainerBindings`.\nThis process can only be done during the initial phase and should not be altered afterwards. \n\nThe fluent binding API begins by calling `Bind\u003cTApparent, TConcrete\u003e`.\n- TApparent: It's the type that can be used when resolving the container.\n- TConcrete: It's type of the actual instance behind the scenes.\n\nLet's see an example\n```csharp\ninterface IInterface;\nclass Implementation : IInterface;\n\nb.Bind\u003cIInterface, Implementation\u003e()...\n...\nc.Resolve\u003cIInterface\u003e() // Succeeds\nc.Resolve\u003cImplementation\u003e() // Runtime error\n```\n\nUse the flunt API available on the returned value of the `Bind` method, to configure the container how it should create, inject, initialize and dispose the instance.\nThe specific binding configuration is done through 9 categories of methods that, by convention, should be done in the order specified below.\n\n```csharp\n// * means source generated\n// ** means ManualDi.Async only\n// *** means ManualDi.Sync only\n\nBind\u003c(TApparent,)* TConcrete\u003e()\n    .Transient***\n    .Default*\n    .From[Constructor*|Instance|Method|MethodAsync**|...]  //There are many more\n    .DependsOn**\n    .Inject\n    .Initialize\n    .Dispose\n    .WithId\n    .When([InjectedIntoId|InjectedIntoType])\n    .[Any other custom extension method your project implements]\n```\n\n`TApparent` is optional and will be equal to `TConcrete` when undefined\n\nWhen you define one or more `TApparent` on a single binding, the underlying `TConcrete` instance will be redirected to each one of them\n\nKeep in mind that you can have more than one binding to the same `TApparent` type. \n\nResolving a type on the container will return the first one that satisfies the resolution rules. (Read more below on `When` binding constraints)\n\n```csharp\nb.Bind\u003cSomeClass\u003e().Default().FromConstructor(); // When calling c.Resolve\u003cSomeClass\u003e() this one is returned\nb.Bind\u003cSomeClass\u003e().Default().FromConstructor();\n```\n### Transient\n\n*** ManualDi.Sync only\n\nWhen this method is used on a binding, the container will create a new instance every time that Binding type is resolved.\nBindings that use `Transient` will not be created if no one resolves them. This means that if you use a Transient binding together with some `Link` extension method, the Transient instance will never be created and thus the `Link` extension method will never be called.\n\nIn the example below, both `A` and `B` will be injected with a brand new instance of `SomeTransient`.\n\n```cssharp\n[ManualDi]\nclass SomeTransient;\n[ManualDi]\nclass A(SomeTransient someTransient);\n[ManualDi]\nclass B(SomeTransient someTransient);\n\nb.Bind\u003cSomeTransient\u003e().Transient().Default().FromConstructor();\nb.Bind\u003cA\u003e().Default().FromConstructor();\nb.Bind\u003cB\u003e().Default().FromConstructor();\n```\n\n\n## Default\n\nThis source generated method is where most of the \"magic\" of the library happens.\nThe source generator will inspect the `TConcrete` type and generate code to register `Inject`, `Initialize` and `InitializeAsync`** methods when available on the type.\nIt will also inspect the type for `IDisposable` or `IAsyncDisposable`** and disable the automatic disposal behaviour when the type does not implement them.\n\nThink of this system as \"duck typing\" via source generation. When the type has a method that matches the expected contract, the container will invoke it.\n\nFor detailed behavior on each of the registered methods, refer to the sections below.\n\nWhen there are multiple candidates for a given method:\n- public methods are preferred over internal ones.\n- in case multiple methods with the same visibility exist, the first one found top-to-bottom is selected.\n\n```csharp\n[ManualDi]\npublic class A;\n[ManualDi]\npublic class B {\n    public void Inject(A a) { } //Sample only, prefer using the constructor\n}\n[ManualDi]\npublic class C {\n    public void Initialize() { }\n}\n[ManualDi]\npublic class D(A a) {\n    public void Inject(C c, A a) { } //Sample only, prefer using the constructor\n    public Task InitializeAsync(CancellationToken ct) { ... }\n}\n\nb.Bind\u003cA\u003e().Default().FromConstructor(); // Default does not call anything\nb.Bind\u003cB\u003e().Default().FromConstructor(); // Default calls Inject\nb.Bind\u003cC\u003e().Default().FromConstructor(); // Default calls Initialize\nb.Bind\u003cD\u003e().Default().FromConstructor(); // Default calls Inject and InitializeAsync\n```\n\nUsing `Default` is not required, but is the recommended pattern this library encourages.\nBy using it, developers only need to implement standardized DI boilerplate once.\nAny subsequent changes to the types are automatically handled by the source generator.\nFor this reason, it’s best to always include it, even when the type doesn’t initially define any of the methods.\n\n## From\n\nThe `From` methods define the instantiation strategy the container should use for each binding.\n\n### Constructor\n\nThis method is source generated ONLY when there is a single `public`/`internal` accessible constructor.\n\nThe container creates the instance using the constructor of the `TConcrete` type. \nAny dependencies necessary on the constructor will get resolved from the container.\n\n```csharp\nb.Bind\u003cT\u003e().Default().FromConstructor();\n```\n\n### Instance\n\nThe container does not create the instance. It is provided externally and used as-is.\n\n```csharp\nb.Bind\u003cT\u003e().Default().FromInstance(new T())\n```\n\n### Method\n\nThe instance is created using the provided delegate. \n\nThe delegate receives the container as a parameter, allowing it to resolve any required dependencies. \n\n```csharp\nb.Bind\u003cT\u003e().Default().FromMethod(c =\u003e new T(c.Resolve\u003cSomeService\u003e()))\n```\n\n### MethodAsync \n(**ManualDi.Async only)\n\nThe instance is created using the provided async delegate.\n\nThe delegate receives the container as a parameter, allowing it to resolve any required dependencies.\n\nThe delegate also receives a cancellation token. That cancellation token will be canceled instantly when the container is disposed.\n\n```csharp\nb.Bind\u003cT\u003e().Default().FromMethodAsync(async (c, ct) =\u003e {\n    // Work can be delayed for any reason\n    // For example: HttpRequests, Loading from disk, etc\n    await Task.Delay(300, ct); \n    return new T(c.Resolve\u003cSomeService\u003e())\n    });\n```\n\n### ContainerResolve\n\nYou will rarely need to call this one.\nUsed for apparent type remapping. Or in other words, used to reexpose some binding as another binding.\nDon't call `Default` when using this, otherwise you get multiple calls on `Inject`, `Initialize` and `InitializeAsync`** more than once\n\nIn the example below, there is `SomeClass` that is bound individually and then two more bindings expose the `SomeClass`\n```csharp\ninterface IFirst;\ninterface ISecond;\n[ManualDi]\nclass SomeClass : IFirst, ISecond;\n\nb.Bind\u003cSomeClass\u003e().Default().FromConstructor();\nb.Bind\u003cIFirst, SomeClass\u003e().FromContainerResolve();\nb.Bind\u003cISecond, SomeClass\u003e().FromContainerResolve();\n```\n\nHowever the recommended pattern when implementing this is to use the `Bind` overload with multiple `TApparent`\n\n```csharp\nb.Bind\u003cIFirst, ISecond, SomeClass\u003e().Default().FromConstructor();\n```\n\n\n## Inject\n\nThe `Inject` method allows for post-construction injection of types. \n\nAvoid running any logic within `Inject` methods, only assign member variables with the parameters provided. All initialization logic is meant to be run on `Initialize` calls.\n\nBinding injection happens in reverse dependency order. Injected objects will already be injected themselves.\n\nThe injection can be used to hook into the object creation lifecycle and run custom code. Each individual binding can have any amount of Inject calls that will be run in the order added.\n\nAs stated on the `Default` section, calling that source generated method will handle the registration of the`Inject` method on `TConcrete` automatically.\n\nThe inject method has two usecases\n1. Inject dependencies when the constructor can't be used (this happens for instance in unity3d where all UnityEngine.Object can't use the constructor)\n2. Workaround Cyclic dependencies that prevent the object graph from being wired\n\n**Warning**: Cyclic dependencies usually highlight a problem in the design of the code. If you find such a problem in your codebase, consider redesigning the code before applying the proposal below.\n\nThis snippet below is an example of a cyclic dependency. It is not possible to implement this with ManualDi nor manually.\n\n```csharp\n[ManualDi]\npublic class A(B b);\n[ManualDi]\npublic class B(A a);\n```\n\nIn order to fix this, while keeping the same design, even if not recommended, the chain must be broken using the `Inject` method.\n\nWhen using `ManualDi.Async` adding the `CyclicDependency`** attribute is also necessary in order to break down cyclic dependencies. Without the attribute it might work, but just due to chance. Using it, will update the creation order of dependencies to avoid issues.\n\n```csharp\n[ManualDi]\npublic class A(B b);\n[ManualDi]\npublic class B\n{\n    public void Inject(A a) { } //ManualDi.Sync this will work\n    public void Inject([CyclicDependency] A a) { } //ManualDi.Async\n}\n```\n\nNote: When dealing with cyclic dependencies, the usual method execution order may not hold.\nNormally, Initialize is called on a type’s dependencies before being called on the type itself.\nHowever, with cyclic dependencies, this order cannot be guaranteed given the types are already breaking the necessary contract for this to be possible. When this happens,additional synchronization logic on those types may be required in order to ensure correct behavior.\nThat said, cyclic dependencies are often a sign of flawed design. If you encounter them, it’s usually better to refactor the architecture rather than patch around the issue.\n\nWhile you should always keep an eye for cyclic dependencies while designing your object graph, you will quickly notice them once you run your application given it won't be able to start and fail during the building process of the container.\n\n## Initialize\n\nThe Initialize method allows for post-injection initialization of types.\n\nBinding initialization is done in reverse dependency order. Initialized objects will already be initialized themselves.\n\nThe initialization can be used to hook into the object creation lifecycle and run custom code. Each individual binding can have any amount of Initialize calls that will be run in the order added.\n\nThe initialization will not happen more than once for any instance.\n\nAs stated on the `Default` section, calling that source generated method will handle the registration of the `Initialize` method automatically.\n\n\n```csharp\nb.Bind\u003cobject\u003e()\n    .FromInstance(new object())\n    .Initialize((o, c) =\u003e Console.WriteLine(\"1\"))  // When object is resolved this is called first\n    .Initialize((o, c) =\u003e Console.WriteLine(\"2\")); // And then this is called\n```\n\nIn the example below, `A.Initialize` will be invoked first and then `B.Initialize` given `B` depends on `A`\n\n\n```csharp\n[ManualDi]\nclass A\n{\n    void Initialize() { }\n}\n\n[ManualDi]\nclass B(A a)\n{    \n    void Initialize() { }\n}\n\n//This is the manual implementation without Default\nb.Bind\u003cA\u003e().FromConstructor().Initialize((o, c) =\u003e o.Initialize()));\nb.Bind\u003cB\u003e().FromConstructor().Initialize((o, c) =\u003e o.Initialize());\n\n//And this is the equivalent and simpler implementation with Default\nb.Bind\u003cA\u003e().Default().FromConstructor();\nb.Bind\u003cB\u003e().Default().FromConstructor();\n```\n\nCreating custom extension methods that call Initialize is the recommended way to supercharge the container.\n\n### Example: Interconnect some features\n\n```csharp\n[ManualDi]\nclass SomeFeature : IFeature;\n\nb.Bind\u003cSomeFeature\u003e()\n    .Default()\n    .FromConstructor()\n    .LinkFeature();\n```\n\nImagine you have an `IFeature` interface in your project and you want to add some shared initialization code to the ones that have it. You can add this reusable code as \"Link\" extension method. Internally these extension methods can use the `Inject`/`Initialize` methods and add whatever extra logic the feature requires.\n\nYou may find further Link examples already present in the library [here](https://github.com/PereViader/ManualDi/blob/540cb3d3155d81dc8925d9ab5769d2a18e61e81b/ManualDi.Unity3d/Assets/ManualDi.Unity3d/Runtime/Extensions/TypeBindingLinkExtensions.cs#L8)\n\n## Dispose\n\nWhen an object implements the `IDisposable` or `IAsyncDisposable`** interface, it doesn't need a manual `Dispose` call in the binding; it will be disposed of automatically.\n\nUsing the `Default` source-generated method provides a slight optimization by skipping a runtime check for IDisposable and IAsyncDisposable.\n\nThe `Dispose` extension method allows defining behavior that will run when the object is disposed.\nThe container will dispose of the objects when itself is disposed.\nThe objects will be disposed in reverse dependency order.\n\nUsing the `Dispose` is fine when readability is preferred, however notice that this method is just a shorthand for calling `QueueDispose` within an `Inject` callback. Calling `QueueDipose` directly is preferred when you want performance. \n\nThe delegates registered on `Dispose`/`QueueDispose` methods will always be run regardless of `SkipDisposable` being used.\n\n```csharp\n[ManualDi]\nclass A : IDisposable \n{ \n    public void Dispose() { }    \n}\n\n[ManualDi]\nclass B(A a)\n{\n    public void DoCleanup() { }\n}\n\nb.Bind\u003cA\u003e().Default().FromConstructor(); // No need to call Dispose because the object is IDisposable\nb.Bind\u003cB\u003e().Default().FromConstructor().Dispose((o,c) =\u003e o.DoCleanup());\n\nc.Dispose(); // A is the first object disposed, then B\n```\n\n### SkipDisposable\n\nWhen this extension method is used, the container skips the runtime check for `IDisposable` and `IAsyncDisposable`** during the disposal phase for the instance where it is used and, consequently, does not dispose the instance.\n\nDelegates registered using the `Dispose`/`QueueDispose` methods will still be invoked.\n\n\n## WithId\n\nThese extension methods allow defining an id, enabling the filtering of elements during resolution.\n\n```csharp\nb.Bind\u003cint\u003e().FromInstance(1).WithId(\"Potato\");\nb.Bind\u003cint\u003e().FromInstance(5).WithId(\"Banana\");\n\n// ...\n\nc.Resolve\u003cint\u003e(x =\u003e x.Id(\"Potato\")); // returns 1\nc.Resolve\u003cint\u003e(x =\u003e x.Id(\"Banana\")); // returns 5\n```\n\nNote: This feature can be nice to use, prefer using it sparingly. This is because it introduces the need for the provider and consumer to share two points of information (Type and Id) instead of just one (Type)\n\nAn alternative to it is to register delegates instead. Delegates used this way encode the two concepts into one.\n\n```csharp\ndelegate int GetPotatoInt();\ndelegate int GetBananaInt();\n\nb.Bind\u003cGetPotatoInt\u003e().FromInstance(() =\u003e 1);\nb.Bind\u003cGetPotatoInt\u003e().FromInstance(() =\u003e 2);\n\nint value1 = c.Resolve\u003cGetPotatoInt\u003e()(); // 1\nint value2 = c.Resolve\u003cGetBananaInt\u003e()(); // 2\n```\n\n### Source generator\n\nThe id functionality can be used on method and property dependencies by using the Inject attribute and providing a string id to it\n\n```csharp\n[ManualDi]\nclass A(int a, [Id(\"Other\")] object b);\n\nb.Bind\u003cA\u003e().Default().FromConstructor();\n\n//Within FromConstructor the snippet below will run\nnew A(\n    c.Resolve\u003cint\u003e(),\n    c.Resolve\u003cobject\u003e(x =\u003e x.Id(\"Other\"))\n)\n```\n\n## When\n\nThe `When` extension method allows defining filtering conditions as part of the bindings.\n\n### InjectedIntoType\n\nAllows filtering bindings by the `TConcrete` type of the Binding where it is being injected to.\n\n```csharp\n[ManualDi]\nclass SomeValue(int Value);\n[ManualDi]\nclass OtherValue(int Value);\n[ManualDi]\nclass FailValue(int Value);\n\nb.Bind\u003cint\u003e().FromInstance(1).When(x =\u003e x.InjectedIntoType\u003cSomeValue\u003e());\nb.Bind\u003cint\u003e().FromInstance(2).When(x =\u003e x.InjectedIntoType\u003cOtherValue\u003e());\n\nb.Bind\u003cSomeValue\u003e().Default().FromConstructor(); // will be provided 1\nb.Bind\u003cOtherValue\u003e().Default().FromConstructor(); // will be provided 2\nb.Bind\u003cFailValue\u003e().Default().FromConstructor(); // will fail at runtime when resolved\n```\n\n### InjectedIntoId\n\nAllows filtering bindings by the id of the Binding where it is being injected to.\n\n```csharp\n[ManualDi]\nclass SomeValue(int Value);\n\nb.Bind\u003cint\u003e().FromInstance(1).When(x =\u003e x.InjectedIntoId(\"1\"));\nb.Bind\u003cint\u003e().FromInstance(2).When(x =\u003e x.InjectedIntoId(\"2\"));\n\nb.Bind\u003cSomeValue\u003e().Default().FromConstructor().WithId(\"1\"); // will be provided 1\nb.Bind\u003cSomeValue\u003e().Default().FromConstructor().WithId(\"2\"); // will be provided 2\nb.Bind\u003cFailValue\u003e().Default().FromConstructor(); // will fail at runtime when resolved\n```\n\n# BindSubContainer\n\nThe instance is created using a sub-container built via the provided installer.\nThis is useful for encapsulating parts of the object graph into isolated sub-containers.\nThe sub-container inherits from the main container, allowing its bindings to depend on types registered in the parent.\nWhen using this approach, do not call `Default` on the main binding. Default should be invoked within the sub-container’s installation instead.\n\nQuestion: When/Why would I do this?\nAnswer: For instance, think of a Unity3d game that has many enemies on a scene and you want to bind all enemies to the container so that their dependencies are setup and it is properly initialized. By doing this, each enemy can have its own independent container scope and object graph. \n\n```csharp\n[ManualDi]\nclass ParentDependency;\n[ManualDi]\nclass SubDependency;\n[ManualDi]\nclass Enemy : MonoBehaviour\n{ \n    public void Inject(ParentDependency parentDependency, SubDependency subDependency) { }\n    public void Initialize() { }\n}\n\nb.Bind\u003cParentDependency\u003e().Default().FromConstructor();\nforeach(var enemy in enemiesInScene)\n{\n    b.BindSubContainer\u003cEnemy\u003e(sub =\u003e {\n        sub.Bind\u003cEnemy\u003e().Default().FromInstance(enemy);\n        sub.Bind\u003cSubDependency\u003e().Default().FromConstructor();\n    });\n}\n```\n\n### BindIsolatedSubContainer\n\nWorks just like `BindSubContainer` but the subcontainer will not inherit from the main container.\nThus nothing from the main container will be resolvable. \n\n```csharp\n[ManualDi]\nclass Enemy : MonoBehaviour\n{ \n    public void Inject(SubDependency subDependency) { }\n}\n[ManualDi]\nclass SubDependency {}\n\nforeach(var enemy in enemiesInScene)\n{\n    b.BindIsolatedSubContainer\u003cEnemy\u003e(sub =\u003e {\n        sub.Bind\u003cEnemy\u003e().Default().FromInstance(enemy);\n        sub.Bind\u003cSubDependency\u003e().Default().FromConstructor();\n    });\n}\n```\n\n# Installers\n\nIn order to group features in a sensible way, bindings should be grouped on Installer classes.\nThese classes may be implemented either as object instances that implement `IInstaller` or as extension methods.\nUnless you explicitly need to use actual instances, this library recommends using extension methods, given they can be used without creating garbage.\n\n```csharp\n[ManualDi]\nclass A;\n[ManualDi]\nclass B;\ninterface IC;\n[ManualDi]\nclass C : IC;\n\n//Extension method installer (recommended)\nstatic class SomeFeatureInstaller\n{\n    public static DiContainerBindings InstallSomeFunctionality(this DiContainerBindings b)\n    {\n        b.Bind\u003cA\u003e().Default().FromInstance(new A());\n        b.Bind\u003cB\u003e().Default().FromConstructor();\n        b.Bind\u003cIC, C\u003e().Default().FromConstructor();\n        return b;\n    }\n}\n\n//Installer instance \nclass SomeFeatureInstaller : IInstaller\n{\n    public static DiContainerBindings Install(DiContainerBindings b)\n    {\n        b.Bind\u003cA\u003e().Default().FromInstance(new A());\n        b.Bind\u003cB\u003e().Default().FromConstructor();\n        b.Bind\u003cIC, C\u003e().Default().FromConstructor();\n        return b;\n    }\n}\n```\n\n# Building different object graphs at runtime\n\nA common requirement when implementing gamemodes, doing A/B tests or taking any other data driven approach is to build different object graphs.\n\nThis can be accomplished in ManualDi by conditionally running different Bind statements.\n\nThe conditional logic can rely for example on external parameters provided to the installer.\n\n```csharp\nstatic class SomeFeatureInstaller\n{\n    public static DiContainerBindings InstallSomeFunctionality(this DiContainerBindings b, bool isEnabled)\n    {\n        if(isEnabled)\n        {\n            b.Bind\u003cISomeFeature, EnabledSomeFeature\u003e().Default().FromConstructor();\n        }\n        else\n        {\n            b.Bind\u003cISomeFeature, DisabledSomeFeature\u003e().Default().FromConstructor();\n        }\n        return b;\n    }\n}\n```\n\nThis however requires adding parameters on installers which is not possible in all cases and can require undesired bolierplate.\n\nAnother way to do this is by resolving instances during the binding process of the container.\n\nThe available resolution methods available on `DiContainerBinding` are:\n- ResolveInstance\n- TryResolveInstance\n- ResolveInstanceNullable\n- ResolveInstanceNullableValue\n\nBindings that are created using `FromInstance` can be resolved from `DiContainerBindings` after they have been bound. Keep in mind that instances are provided 'as is,' without any initialization or callbacks performed, because at the time of installation nothing will have been triggered yet.\n\nWhen `WithParentContainer` is used, all bindings on the parent can container can be resolved\n\nWhen `BindSubContainer` is used, the subcontainer can access the same the base installer could\n\nKeep in mind that using this is not always necessary you can also provide parameters on extension method / instance installers. However this is not always possible and can introduce a lot of boilerplate thus adding complexity for little gain. Using this feature trades compilation safety for fewer bolierplate, thus you need to weight what is the best approach for your use case.\n\nThis could be some sample feature implemented using this\n\n```csharp\n//On some installer do\nb.Bind\u003cSomeConfig\u003e().FromInstance(new SomeConfig(IsEnabled: true))\n\n//On another installer for the same container do\nvar config = b.ResolveInstance\u003cSomeConfig\u003e();\nif(config.IsEnabled)\n{\n    b.Bind\u003cISomeFeature, EnabledSomeFeature\u003e().Default().FromConstructor();\n}\nelse\n{\n    b.Bind\u003cISomeFeature, DisabledSomeFeature\u003e().Default().FromConstructor();\n}\n```\n\nWhen doing A/B tests and doing continuous integration, my recommendation is that you implement some feature flag source that is always available and allows you to conditionally toggle features on and off easily without needing to have a custom config for each one\n\n```csharp\n//On some installer for the parent container do\nb.Bind\u003cIFeatureFlags, FeatureFlags\u003e().Default().FromConstructor();\n\n//On another installer for child container\nvar featureFlags = b.ResolveInstance\u003cIFeatureFlags\u003e();\nif(featureFlags.IsEnabled(FeatureFlagConstants.SomeFeature))\n{\n    b.Bind\u003cISomeFeature, EnabledSomeFeature\u003e().Default().FromConstructor();\n}\nelse\n{\n    b.Bind\u003cISomeFeature, DisabledSomeFeature\u003e().Default().FromConstructor();\n}\n```\n\n# Failure debug report\n(ManualDi.Async**)\n\nAn async object graph might sometimes be complicated to understand the order things will run. When an exception happens during the DiContainer creation and initialization it can sometimes be difficult to understand why.\n\nThe failure debug report adds more data when an exception to the exception so that you can better understand the order in which things run.\n\nThis feature is opt in and can be used by enabling it on `DiContainerBindings`\n\n```csharp\ntry\n{\n    await using var container = await new DiContainerBindings()\n        .Install(b =\u003e\n        {\n            b.Bind\u003cobject\u003e()\n                .DependsOn(x =\u003e x.ConstructorDependency\u003cint\u003e())\n                .FromMethod(x =\u003e throw new Exception());\n            b.Bind\u003cint\u003e();\n        })\n        .WithFailureDebugReport()  // enable the report\n        .Build(CancellationToken.None);\n}\ncatch (Exception e)\n{\n    var report = (string)e.Data[DiContainer.FailureDebugReportKey]!; // get the report\n    //use this report to check the order of dependencies \n    return;\n}\n```\n\nThe report will return the order of creation, injection and initialization. The example above returns \n\n```csharp\nApparent: System.Int32, Concrete: System.Int32, Id: \nApparent: System.Object, Concrete: System.Object, Id: \n```\n\nNote: If you think there is some other piece of data that should be added open a discussion with the suggestion.\n\n\n# Extra Source Generator features\n\n## Nullable\n\nThe source generator will take into account the nullability of the dependencies.\nIf a dependency is nullable, the resolution will not fail if it is missing.\nIf a dependency is not nullable, the resolution will fail if it is missing.\n\n```csharp\n[ManualDi]\npublic class A\n{\n    //object MUST be registered on the container\n    //int may or may not be registered on the container\n    public A(object obj, int? nullableValue) { }\n}\n\n//This will create an instance of A with an object instance and a null int\nb.Bind\u003cA\u003e().Default().FromConstructor();\nb.Bind\u003cobject\u003e.Default().FromInstance();\n```\n\n## Collection\n\nThe source generator will inject all bound instances of a type if the dependency declared is one of the following types `List\u003cT\u003e` `IList\u003cT\u003e` `IReadOnlyList\u003cT\u003e` `IEnumerable\u003cT\u003e`\nThe resolved dependencies will be resolved using `ResolveAll\u003cT\u003e`\n\nIf the collection itself is declared nullable (e.g., `List\u003cT\u003e?`), it will be `null` if no matching bindings are found. Otherwise (e.g. `List\u003cT\u003e`), an empty list will be injected if no matching bindings are found. In both cases, when no matching bindings exist, the list will contain those instances found.\nIf the generic type argument `T` is nullable (e.g., `List\u003cT?\u003e`), the source generator will accommodate this. This is generally not recommended, as bindings are always expected to return non-null instances.\n\n\n\n```csharp\n[ManualDi]\npublic class A\n{\n    public A(\n        List\u003cobject\u003e listObj,\n        IList\u003cint\u003e iListInt,\n        IReadOnlyList\u003cobj\u003e iReadOnlyListObj,\n        IEnumerable\u003cint\u003e iEnumerableInt,\n        List\u003cobject\u003e? nullableList, //Either null or Count \u003e 0\n        List\u003cobject?\u003e nullableGenericList //Valid but NOT recommended\n        )\n    {\n    }\n}\n\nb.Bind\u003cA\u003e().Default().FromConstructor();\n```\n\n# Resolving\n\nNotice that resolution can only be done on apparent types, not concrete types. Concrete types are there so the container can provide a type safe fluent API.\n\nYou should rarely use these methods, only using them when implementing reusable Link methods or some very edge case logic. Under most circumpstances you should rely on the source generated methods that implement calling these for you.\n\nResolutions can be done in the following ways:\n\n## Resolve\n\nResolve an instance from the container. An exception is thrown if it can't be resolved.\n\n```csharp\nSomeService service = container.Resolve\u003cSomeService\u003e();\n```\n\n## ResolveNullable\n\nResolve a reference type instance from the container. Returns null if it can't be resolved.\n\n```csharp\nSomeService? service = container.ResolveNullable\u003cSomeService\u003e();\n```\n\n## ResolveNullableValue\n\nResolve a value type instance from the container. Returns null if it can't be resolved.\n\n```csharp\nint? service = container.ResolveNullableValue\u003cint\u003e();\n```\n\n## TryResolve\n\nResolve an instance from the container. Returns true if found and false if not.\n\n```csharp\nbool found = container.TryResolve\u003cSomeService\u003e(out SomeService someService);\n```\n\n## ResolveAll\n\nResolve all the registered instance from the container. If no instances are available the list is empty.\n\n```csharp\nList\u003cSomeService\u003e services = container.ResolveAll\u003cSomeService\u003e();\n```\n\n# Startups\n\nThe container provides functionality that queues work to be done once the container is built and ready.\nBy using this you can define the entry points of your application declaratively during the installation of the container.\n\n```csharp\n[ManualDi]\nclass Startup(SomeService someService)\n{\n    public void Start() { ... }\n}\n\n[ManualDi]\nclass SomeService\n{\n    public void Initialize() { ... }\n}\n\nb.Bind\u003cSomeService\u003e().Default().FromConstructor();\nb.Bind\u003cStartup\u003e().Default().FromConstructor();\nb.QueueStartup\u003cStartup\u003e(o =\u003e o.Start());\n```\n\nIn the snippet above, the following will happen when the container is built:\n- `SomeService` is created\n- `Startup` is created\n- `SomeService`'s `Initialize` method is called\n- `Startup`'s `Start` method is called\n\n## Tradeoffs\n\nManualDi is not perfect, it does have some tradeoffs, that of course in my opinion are completely worth it.\n\nPositive:\n- Less code: Because the code is implemented using source generation and using a dynamic layer that handles the execution order, there is much less code to write. A single line of ManualDi code handles: creation, disposal and order of execution.\n- Agile: Because there is less code to write and the code to write is updated automatically when requirements change, the team can be faster.\n- Fewer source control conflicts: Because each component is implemented in isolation to the others, source control conflicts are much less likely to happen.\n- Dynamically configurable: ManualDi can create dependencies with different types at runtime easily. Compile safe code requires adding even more code when anything like it.\n\nNegative:\n\n- Not compile safe: Because the container is adding a dynamic layer, the compiler can't verify all the required dependencies are properly registered. \n- Slower: Because the container is adding a dynamic layer, the indirection makes the code slower than the compile safe conuterpart.\n    - Even if slower, ManualDi is significally fast to the point where it is usually not a problem\n\n\n\n---\n# Unity3d\nFrom this point below, the documentation is Unity3d integration specific.\n\nWhen using the container in unity, avoid relying on `Awake` / `Start`. Instead, rely on Inject / Initialize / InitializeAsync.\nYou may still use `Awake` / `Start` if the classes involved are not injected through the container.\n\nBy relying on the container and not on native Unity3d callbacks you can be certain that the dependencies of your classes are Injected and Initialized in the proper order.\n\n## Installers\n\nThe container provides two specialized Installers \n- `MonoBehaviourInstaller` \n- `ScriptableObjectInstaller`\n\nThis is the idiomatic Unity way to have both the configuration and engine object references in the same place.\nUsing these classes is not required, they are just abstract classes that implement `IInstaller`. Feel free to use `IInstaller` directly if you prefer that.\n\n```csharp\npublic class SomeFeatureInstaller : MonoBehaviourInstaller\n{\n    public Image Image;\n    public Toggle Toggle;\n    public Transform Transform;\n\n    public override void Install(DiContainerBindings b)\n    {\n        b.Bind\u003cImage\u003e().FromInstance(Image);\n        b.Bind\u003cToggle\u003e().FromInstance(Toggle);\n        b.Bind\u003cTransform\u003e().FromInstance(Transform);\n    }\n}\n```\n\n## Binding\n\nWhen using the container in the Unity3d game engine the library provides specialized extensions for object construction\n\n- `FromGameObjectGetComponent`: Retrieves a component directly from a given GameObject.\n- `FromGameObjectGetComponentInChildren`: Retrieves a component from the children of a given GameObject.\n- `FromGameObjectGetComponentInParent`: Retrieves a component from the parent of a given GameObject.\n- `FromGameObjectAddComponent`: Adds a new component to a GameObject and optionally schedules it for destruction on disposal.\n- `FromInstantiateComponent`: Instantiates a given component, optionally setting a parent and scheduling it for destruction on disposal.\n- `FromInstantiateGameObjectGetComponent`: Instantiates a GameObject and retrieves a specific component from it.\n- `FromInstantiateGameObjectGetComponentInChildren`: Instantiates a GameObject and retrieves a component from one of its children.\n- `FromInstantiateGameObjectAddComponent`: Instantiates a GameObject and adds a new component to it.\n- `FromAsyncInstantiateOperation`**: Binds using a user-supplied asynchronous component instantiation operation.\n- `FromAsyncInstantiateOperationGetComponent`**: Asynchronously instantiates a GameObject and retrieves a specific component from it.\n- `FromLoadSceneAsyncGetComponent`**: Loads a scene additively and retrieves a specific component from the root GameObjects of the scene.\n- `FromLoadSceneAsyncGetComponentInChildren`**: Loads a scene additively and retrieves a specific component from any children in the root GameObjects of the scene.\n- `FromAddressablesLoadAssetAsync`**: Asynchronously loads an asset from the Addressables system using a key.\n- `FromAddressablesLoadAssetAsyncGetComponent`**: Loads a GameObject asset from Addressables and retrieves a component from it.\n- `FromAddressablesLoadAssetAsyncGetComponentInChildren`**: Loads a GameObject asset from Addressables and retrieves a component from its children.\n- `FromAddressablesLoadSceneAsyncGetComponent`**: Loads a scene via Addressables and retrieves a specific component from the root GameObjects of the scene.\n- `FromAddressablesLoadSceneAsyncGetComponentInChildren`**: Loads a scene via Addressables and retrieves a specific component from the root GameObjects of the scene.\n- `FromObjectResource`: Loads an object from the Unity Resources folder.\n- `FromInstantiateGameObjectResourceGetComponent`: Instantiates a GameObject from the Resources folder and retrieves a component from it.\n- `FromInstantiateGameObjectResourceGetComponentInChildren`: Instantiates a GameObject from the Resources folder and retrieves a component from one of its children.\n- `FromInstantiateGameObjectResourceAddComponent`: Instantiates a GameObject from the Resources folder and adds a new component to it.\n\n\nUse them like this.\n\n```csharp\npublic class SomeFeatureInstaller : MonoBehaviourInstaller\n{\n    public Transform canvasTransform;\n    public string ResourcePath;\n    public Toggle TogglePrefab;\n    public GameObject SomeGameObject;\n    public AddressableReference SceneReference;\n\n    public override Install(DiContainerBindings b)\n    {\n        b.Bind\u003cToggle\u003e().FromInstantiateComponent(TogglePrefab, canvasTransform);\n        b.Bind\u003cImage\u003e().FromInstantiateGameObjectResourceGetComponent(ResourcePath);\n        b.Bind\u003cSomeFeature\u003e().Default().FromGameObjectGetComponent(SomeGameObject);\n        b.Bind\u003cSceneReferences\u003e().Default().FromAddressablesLoadAssetAsyncGetComponent(SceneReference);\n    }\n}\n```\n\nThere is no need to remember them exactly, just use your IDE autocomplete functionality.\n\nUnityEngine.Object dependancies should be serialized on installers and bound during installation.\n\nMost of the From methods that do instantiation, have several optional parameters. For instance:\n- `Transform? parent = null` defines the parent transform used when instantiating new instances.\n- `bool destroyOnDispose = true` will cleanup instanciated instances upon disposal of the container\n\n## EntryPoints\n\nAn entry point is the place where some context of your application is meant to start.\nIn the case of ManualDi, it is where the object graph is configured and then the container is started.\n\nThe last binding of an entry point will usually make use of QueueStartup, to actually initiate the behaviour for the context it represents.\n\nIn simple terms, an EntryPoint is a root Installer where you call other Installers from \n\n### RootEntryPoint\n\nRoot entry points will not depend on any other container.\nRoot entry points may be started either manually or on the Unity Start callback. This is configured through the inspector.\n\nUse the appropriate type depending on how you want to structure your application:\n- `MonoBehaviourRootEntryPoint`\n- `ScriptableObjectRootEntryPoint`\n\n```csharp\npublic class Startup\n{\n    public Startup(Dependency1 d1, Dependency2 d2) { ... }\n    public void Start() { ... }\n}\n\nclass InitialSceneEntryPoint : MonoBehaviourRootEntryPoint\n{\n    public Dependency1 dependency1;\n    public Dependency2 dependency2;\n\n    public override void Install(DiContainerBindings b)\n    {\n        b.Bind\u003cDependency1\u003e().Default().FromInstance(dependency1);\n        b.Bind\u003cDependency2\u003e().Default().FromInstance(dependency2);\n        b.Bind\u003cStartup\u003e().Default().FromConstructor();\n        b.QueueStartup\u003cStartup\u003e(o =\u003e o.Start());\n    }\n}\n```\n\n### SubordinateEntryPoint\n\n \nSubordinate entry points cannot are entry points that can not be started by themselves. \nThey need to be started by some other part of your application because they depend on external data / container.\nThese entry points may optionally also return some `TFacade` to the caller.\n\nThe data provided to the container is available on the entrypoint through the `Data` property.\nWhen the data implements `IInstaller` it is also installed to the container.\nWhen access to a parent container is necessary, doing it on the data type is the recommended pattern.\n\n```csharp\npublic class EntryPointData : IInstaller\n{\n    public IDiContainer ParentDiContainer { get; set; }\n\n    public void Install(DiContainerBindings b)\n    {\n        b.WithParentContainer(ParentDiContainer);\n    }\n}\n```\n\nThese entry points may also optionally return a `TContext` object resolved from the container.\n\nThat `TContext` can be used as a facade for the external system to interact with it.\n\nUse the appropriate type depending on how you want to structure your application:\n- `MonoBehaviourSubordinateEntryPoint\u003cTData\u003e`\n- `MonoBehaviourSubordinateEntryPoint\u003cTData, TContext\u003e`\n- `ScriptableObjectSubordinateEntryPoint\u003cTData\u003e`\n- `ScriptableObjectSubordinateEntryPoint\u003cTData, TContext\u003e`\n\nNote: MonoBehaviour ones will probably be the most common\n\n```csharp\npublic class Startup\n{\n    public Startup(Dependency1? d1, Dependency2 d2) { ... }\n    public void Start() { ... }\n}\n\npublic class EntryPointData : IInstaller\n{\n    public Dependency1? Dependency1 { get; set; }\n\n    public void Install(DiContainerBindings b)\n    {\n        if(Dependency1 is not null)\n        {\n            b.Bind\u003cDependency1\u003e().FromInstance(Dependency1).SkipDisposable();\n        }\n    }\n}\n\npublic class Facade : MonoBehaviour\n{\n    private Dependency1? _dependency1;\n    private Dependency2 _dependency2;\n\n    public void Inject(Dependency1? dependency1, Dependency2 dependency2)\n    {\n        _dependency1 = dependency1;\n        _dependency2 = dependency2;\n    }\n\n    public void DoSomething1()\n    {\n        _dependency1?.DoSomething1();\n    }\n\n    public void DoSomething2()\n    {\n        _dependency2.DoSomething2();\n    }\n}\n\nclass InitialSceneEntryPoint : MonoBehaviourSubordinateEntryPoint\u003cEntryPointData, Facade\u003e\n{\n    public Dependency2 dependency2;\n    public Facade Facade;\n\n    public override void Install(DiContainerBindings b)\n    {\n        b.Bind\u003cDependency2\u003e().Default().FromInstance(dependency2);\n        b.Bind\u003cFacade\u003e().Default().FromInstance(Facade);\n        b.Bind\u003cStartup\u003e().Default().FromConstructor();\n        b.QueueStartup\u003cStartup\u003e(o =\u003e o.Start());\n    }\n}\n```\n\nAnd this is an example of how a subordinate entry point on a scene or as a prefab could be initiated\n\n```csharp\npublic class Data\n{\n    public string Name { get; set; }\n}\n\npublic class SceneFacade\n{\n    private readonly Data _data;\n\n    public SceneFacade(Data _data) \n    {\n        _data = data;\n    }\n\n    public void DoSomething() \n    {  \n        Console.WriteLine(data.Name);\n    }\n}\n\npublic class SceneEntryPoint : MonoBehaviourSubordinateEntryPoint\u003cData, SceneFacade\u003e\n{\n    public override void Install(DiContainerBindings b)\n    {\n        b.Bind\u003cData\u003e().Default().FromInstance(Data);\n        b.Bind\u003cSceneFacade\u003e().Default().FromConstructor();\n    }\n}\n\nclass Example\n{\n    async Task Run()\n    {\n        await SceneManager.LoadSceneAsync(\"TheScene\", LoadSceneMode.Additive);\n        \n        var entryPoint = Object.FindObjectOfType\u003cSceneEntryPoint\u003e();\n        var data = new Data() { Name = \"Charles\" };\n        var facade = entryPoint.Initiate(data)\n        \n        facade.DoSomething();\n    }\n}\n```\n\nand this is an example of how you could initiate a subordinate entry point that is part of a prefab\n\n\n```csharp\nclass Example : MonoBehaviour\n{\n    public SceneEntryPoint EntryPointPrefab;\n\n    void Start()\n    {        \n        var data = new Data() { Name = \"Charles\" };\n\n        var entryPoint = Instantiate(EntryPointPrefab, transform);\n        var facade = entryPoint.Initiate(data)\n        \n        facade.DoSomething();\n    }\n}\n```\n\nThe container provides you with the puzzle pieces necessary. The actual composition of these pieces is up to you to decide.\nFeel free to ignore the container classes and implement your custom entry points if you have any special need.\n\n## Link\n\nLink methods are a great way to interconnect different features right from the container.\nThe library provides a few, but adding your own custom ones for your use cases is a great way to speed up development.\n\n- `LinkDontDestroyOnLoad`: The GameObject associated with the bound component will have `DontDestroyOnLoad` called on it when the container is bound. Behaviour can be customized with the optional parameters\n\n```csharp\nclass Installer : MonoBehaviourInstaller\n{\n    public SomeService SomeService;\n\n    public override void Install(DiContainerBindings b)\n    {\n        b.Bind\u003cSomeService\u003e()\n            .Default()\n            .FromInstance(SomeService)\n            .LinkDontDestroyOnLoad();\n    }\n}\n```\n\nNote: There is a sample in the package that provides a Tickable system and a LinkTickable extension. This system allows for having Update like behaviour on any class.\n\n\n# How and why does ManualDi help\n\n## Comparing manual creation and injection to ManualDi \nIn order to understand how ManualDi will help you write fewer and better lines of code, let see the difference between a composition root with and without ManualDi.\n\nNote: For the sake of the example, we will use an API inspired by the Unity3d engine. Keep in mind that the Unity3d engine API is not exaclty like the example below.\n\nImagine you have a very simple game with a gameplay scene and a player\n```csharp\nvar gameplayScene = await SceneManager.LoadSceneAsync(\"GameplayScene\");\nvar player = await Addressables.InstantiateAsync\u003cPlayer\u003e(\"Player\");\n\ngameplayScene.Inject(player);\nplayer.Initialize();\n\n...\n\nAddressable.Unload(player)\nSceneManager.UnloadScene(gameplayScene);\n```\n\nNotice that we are doing manual creation and injection of instances followed up by the required initialization calls each component requires.\nLet's some new piece of functionality to the example and observe how it changes. \n\n```csharp\nvar gameplayScene = await SceneManager.LoadSceneAsync(\"GameplayScene\");\nvar player = await Addressables.InstantiateAsync\u003cPlayer\u003e(\"Player\");\nvar saveSystem = new SaveSystem(player)\n\ngameplayScene.Inject(player);\nplayer.Initialize();\nawait saveSystem.InitializeAsync();\ngameplayScene.Initialize();\n\n...\n\nAddressable.Unload(player)\nSceneManager.UnloadScene(gameplayScene);\n```\n\nNotice that we required to add some new piece of creation of injection on top and then called the associated piece of initialization code below.\nNotice that the order of injection and initialization call is very important, those calls cannot be executed in any random way, the order of execution of these methods must be the reverse of dependencies in order to have a logically sound execution.\n\nLet's change the save system to do more work and also handle storing some scene data.\n\n```csharp\nvar gameplayScene = await SceneManager.LoadSceneAsync(\"GameplayScene\");\nvar player = await Addressables.InstantiateAsync\u003cPlayer\u003e(\"Player\");\nvar saveSystem = new SaveSystem(player, gameplayScene)\n\ngameplayScene.Inject(player);\nplayer.Initialize();\ngameplayScene.Initialize();\nawait saveSystem.InitializeAsync();\n\n...\n\nAddressable.Unload(player)\nSceneManager.UnloadScene(gameplayScene);\n```\n\nNotice that in order to keep the rule stated above where depedencies are initialized in reverse dependency order, the initialize call has been moved some lines below.\nNot following this rule is a common source of bugs given components can use non initialized components.\n\nManualDI handles all of this automatically, freeing us from maintaining all of it.\n\nInitially, when just two components were present. The equivalent code using ManualDi would be\n\n```csharp\nb.Bind\u003cGameplayScene\u003e().Default().FromLoadSceneAsync(\"GameplayScene\");\nb.Bind\u003cPlayer\u003e().Default().FromAddressableInstantiate(\"Player\");\n```\n\nThen adding the save SaveSystem\n\n```csharp\nb.Bind\u003cGameplayScene\u003e().Default().FromLoadSceneAsync(\"GameplayScene\");\nb.Bind\u003cPlayer\u003e().Default().FromAddressableInstantiate(\"Player\");\nb.Bind\u003cSaveSystem\u003e().Default().FromConstructor();\n```\n\nNotice that the snippet above works for both when the save system interacts with just the player and both the player and scene. This is because ManualDi alaways runs things in the proper order by taking into account the dependencies of components.\n\nAlso notice that all of the disposal responsabilities are also handled by ManualDi without specifying anything about it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpereviader%2Fmanualdi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpereviader%2Fmanualdi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpereviader%2Fmanualdi/lists"}