C# - DI(Dependency injection)コンテナを使う

DI(Dependency injection)とはオブジェクト間の依存関係をなくすために、クラスの中で必要なインスタンスを生成するのではなく、外で作られたインスタンスをセットするように設計しようという考え方です。

参考:C# - DI(Dependency injection)依存性の注入とは

 

そしてこの設計パターンをサポートしてくれるライブラリがDIコンテナです。

C#では「Microsoft.Extensions.DependencyInjection」というDIコンテナが用意されています。


DIコンテナのインストール

DIコンテナである「Microsoft.Extensions.DependencyInjection」をインストールしましょう。
Visual Studioの NuGetパッケージマネージャーからインストールすることができます。

 

メニューから「プロジェクト(P)」→「NuGet パッケージの管理(N)...」を選択します。

Microsoft.Extensions.DependencyInjectionを検索してインストールボタンをクリックしましょう。


オブジェクトを管理するIServiceCollection

DIで利用するクラスはSerciveCollectionクラスで管理します。

SerciveCollectionクラスに利用するクラスを登録すると、ServiceProviderクラスを介して必要なオブジェクトを取得することができます。

DIしたいクラスを登録

SerciveCollectionクラスには管理するクラスを登録するためのAdd????メソッドがあります。

 

AddSingletonメソッド

このメソッドで登録されたクラスは単一のインスタンスになります。

一度インスタンスが生成されるとアプリが終了するまで同じインスタンスを使いまわします。

 

AddTransientメソッド

このメソッドで登録されたクラスは毎回新しいインスタンスが生成されます。

ServiceProviderクラスのGetServiceメソッドを呼ぶたびに異なるインスタンスとなります。

 

AddScopedメソッド

同一スコープ内では同一のインスタンスとなり別スコープでは別にインスタンスになります。

スコープはServiceProviderクラスのCreateScopeメソッドを使って作られます。

ServiceProviderを生成

クラスの登録が一通り終わったらBuildServiceProviderメソッドを呼び出してServiceProviderを生成します。

オブジェクトを取得

ServiceProviderクラスの以下のメソッドを呼び出してインスタンスを取得します。

 

GetServiceメソッド

インスタンスが作成できない場合、戻り値は null になります。

 

GetRequiredServiceメソッド

インスタンスが作成できない場合、InvalidOperationExceptionが発生します。


利用例

    public class A
    {
        private B TestB;

        public A(B b)
        {
            TestB = b;
        }

        public void Echo()
        {
            System.Console.WriteLine(TestB.GetMessage());
        }
    }



    public interface B
    {
        public string GetMessage();
    }



    public class B1 : B
    {
        public string GetMessage()
        {
            return "クラスB1です";
        }
    }





    class Program
    {
        static void Main(string[] args)
        {
            var services = new ServiceCollection();
            services.AddTransient<B, B1>();
            services.AddTransient<A>();

            var provider = services.BuildServiceProvider();
            var testA = provider.GetRequiredService<A>();
            testA.Echo();
        }
    }

42~43行目でクラスを登録しています。

クラスB1はインターフェースBとして利用したいので、サービスの型がBで実態の型がB1という指定がされています。

 

46行目でクラスAのインスタンスを取得しています。

クラスAはコンストラクタでBを必要としますがServiceProviderが適切に処理してくれています。