コンストラクタインジェクション
コンテナに登録されたクラスは、コンストラクタ定義が走査され、必要に応じて自動的にインスタンスが生成されます。
注記
- コンストラクタの引数もコンテナに登録されている必要があります。
- 依存関係を構築できない場合、コンテナのビルド時に例外 (
VContainerException
) が投げられます。
以下は、コンストラクタを使ったDIの基本的なイディオムです。
class ClassA
{
readonly IServiceA serviceA;
readonly IServiceB serviceB;
readonly SomeUnityComponent component;
public ClassA(
IServiceA serviceA,
IServiceB serviceB,
SomeUnityComponent component)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
this.component = component;
}
}
注意
IL2CPP環境下では、直接参照のないコンストラクタがビルドから削除されてしまう場合があります。
これを防ぐには、[Inject]
アトリビュートをつけて下さい。
[Inject]
public ClassA(
IServiceA serviceA,
IServiceB serviceB,
SomeUnityComponent component)
{
// ...
}
注記
コンストラクタが複数定義されている場合、 [Inject]
アトリビュートがついたものが優先されます。
Recommendation
可能な場合は常にコンストラクタインジェクションを使おう。
コンストラクタとreadonlyフィールドのイディオムには以下のような利点があります。
- インスタンス化されたならば、その時点で依存オブジェクトが揃っていることがコンパイラレベルで保証されます。
- クラスのコードが魔法のない何の変哲もないものになります。DIコンテナなしで手動でインスタンスをつくることも簡単です。(e.g. Unit testing)
- 依存関係を知りたいならコンストラクタ定義だけを見れば良いため、見通しが良くなります。
- もしもコンストラクタの引数が多すぎるなら、クラスの責務が多すぎると判断することができそうです。
Key Attribute
同じインターフェイスや型の複数の実装が異なるキーで登録されている場合、Key
属性を使ってどの実装を注入するかを指定することができます。
class TestClass
{
private readonly IWeapon _primaryWeapon;
private readonly IEnemy _goblin;
private readonly ILevel _level1;
public TestClass(
[Key(WeaponType.Primary)] IWeapon primaryWeapon,
[Key("goblin")] IEnemy goblin,
[Key(1)] ILevel level1)
{
_primaryWeapon = primaryWeapon;
_goblin = goblin;
_level1 = level1;
}
}
注記
[Key]
アトリビュートは、.Keyed()
メソッドを使用して対応するキーを登録した型に使用する必要があります。詳しくはRegister with Keys セクションを参照してください。
MonoBehaviour
MonoBehaviour
はコンストラクタを直接使うことができません。代わりに Method Injection が使えます。