> For the complete documentation index, see [llms.txt](https://docs.parsue.io/aceland-unity-packages/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.parsue.io/aceland-unity-packages/core-packages/injection/injection-points.md).

# Injection Points

An **injection point** is a place you mark so the container knows to supply a value there. AceLand Injection has two families of injection points:

* **Service injection** with `[Inject]` — pulls a value out of the container.
* **Component injection** with `[Self]` / `[Parent]` / `[Child]` / `[FromScene]` / `[AddComponent]` — pulls a component out of the Unity hierarchy.

Both attributes live in the **Abstractions** package, so you can annotate a type without depending on the full runtime.

***

### `[Inject]` — service injection

`[Inject]` can be applied to a **constructor**, a **field**, a **property** (with a setter), a **method**, or a **parameter**. The container resolves each target from its registrations.

{% tabs %}
{% tab title="Constructor" %}

```csharp
using AceLand.Injection;

public sealed class Gameplay
{
    private readonly IScoreService _score;
    private readonly IAudioService _audio;

    // Constructor injection is the preferred style for plain C# services.
    [Inject]
    public Gameplay(IScoreService score, IAudioService audio)
    {
        _score = score;
        _audio = audio;
    }
}
```

{% hint style="info" %}
If a type has exactly one public constructor you usually don't even need `[Inject]` — the container picks it automatically. Use `[Inject]` to disambiguate when several constructors exist.
{% endhint %}
{% endtab %}

{% tab title="Field & property" %}

```csharp
using AceLand.Injection;

// 'partial' → the generator can reach the private field for a zero-reflection plan.
public sealed partial class Hud : MonoBehaviour
{
    [Inject] private IScoreService _score;          // private field
    [Inject] public IAudioService Audio { get; set; } // property with setter

    void Awake() => DI.Inject(this);   // MonoBehaviours ask to be injected
}
```

{% hint style="info" %}
When you inject a **private / protected** field or property, declare the type `partial` so the Source Generator can emit a plan that reaches it. Without `partial` it still works, but injection falls back to reflection and the compiler raises **ACEDI005**. See [Tooling](/aceland-unity-packages/core-packages/injection/tooling.md).
{% endhint %}
{% endtab %}

{% tab title="Method" %}

```csharp
using AceLand.Injection;

public sealed class Analytics
{
    private ITracker _tracker;

    // Every parameter is resolved, then the method is invoked once after construction.
    [Inject]
    public void Configure(ITracker tracker, ILogger logger)
    {
        _tracker = tracker;
        logger.Info("Analytics ready");
    }
}
```

{% endtab %}
{% endtabs %}

#### Optional dependencies

Set `Optional = true` to receive `null` (instead of an exception) when nothing is registered:

```csharp
public sealed class Enemy
{
    [Inject(Optional = true)] private IVoiceService _voice;   // may stay null

    public void Roar() => _voice?.Play("roar");
}
```

#### Keyed dependencies with `Id`

When more than one implementation is registered for the same contract, disambiguate with an `Id` that matches the `WithId(...)` used at registration time:

```csharp
public sealed class Ui
{
    [Inject(Id = "main")]    private ICanvas _mainCanvas;
    [Inject(Id = "overlay")] private ICanvas _overlayCanvas;
}
```

See Registration & Lifetime for the matching `WithId` calls.

***

### Component injection (MonoBehaviours)

For MonoBehaviours you often want a collaborator that already lives in the scene hierarchy rather than something built by the container. The component attributes do exactly that — each maps to a Unity lookup:

<table><thead><tr><th width="159.199951171875">Attribute</th><th width="288.5999755859375">Unity equivalent</th><th>Finds</th></tr></thead><tbody><tr><td><code>[Self]</code></td><td><code>GetComponent</code></td><td>on the <strong>same</strong> GameObject.</td></tr><tr><td><code>[Parent]</code></td><td><code>GetComponentInParent</code></td><td>self and ancestors.</td></tr><tr><td><code>[Child]</code></td><td><code>GetComponentInChildren</code></td><td>self and descendants.</td></tr><tr><td><code>[FromScene]</code></td><td><code>FindObjectsByType</code></td><td>anywhere in the loaded scene.</td></tr><tr><td><code>[AddComponent]</code></td><td><code>GetComponent</code>, else <code>AddComponent</code></td><td>on the same GameObject, adding if missing.</td></tr></tbody></table>

```csharp
using AceLand.Injection;

public class Turret : MonoBehaviour
{
    [Self]         private Rigidbody _body;          // same GameObject
    [Parent]       private Health _health;           // this or an ancestor
    [Child]        private Renderer[] _renderers;    // this or descendants (collection)
    [FromScene]    private GameManager _game;        // anywhere in the scene
    [AddComponent] private AudioSource _audio;       // get, or add when missing

    // Optional = true → stays null instead of throwing when not found.
    [Child(Optional = true)] private Light _optionalLight;
}
```

#### Collections

A component attribute on an **array** or `List<T>` collects *all* matches instead of the first one (as `Renderer[] _renderers` above demonstrates).

#### `IncludeInactive`

Component lookups include inactive objects by default (`IncludeInactive = true`). Set it to `false` to match only active objects:

```csharp
[Child(IncludeInactive = false)] private Collider[] _activeColliders;
```

{% hint style="info" %}
Component injection runs automatically for objects inside an **Injection Scope**, and it completes **before** `Awake` — so the fields are already populated when your `Awake` runs. See Scopes & Containers.
{% endhint %}

***

### How it gets filled in

* Inside an **Injection Scope**: every MonoBehaviour under the scope is injected automatically before `Awake`.
* For a type you build yourself: call `DI.Inject(obj)` (global container) or `resolver.Inject(obj)` (a specific scope).
* For a brand-new instance: `DI.CreateInstance<T>()` constructs *and* injects in one step.

The **Source Generator** emits a zero-reflection plan for each injectable type at compile time; if no plan exists (e.g. the analyzer isn't set up), the runtime falls back to reflection. Either way the behaviour is identical — see Tooling.
