プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2019/02/20

.NET Core で複数のインターフェイスを実装したクラスの DI を行う

event_note2019/02/19 23:55

.NET Core の DI サービスにおいて、複数のインターフェイスを実装したクラスの DI を行う方法について試してみました。

正直これでいいのかなという感じですが・・・。

尚、DI の機能は ASP.NET Core として解説されているものが多いですが、DI の機能自体は Microsoft.Extensions.DependencyInjection で提供されているので、ASP.NET Core に限らず .NET Core のコンソールアプリなどでも使えます。

環境

  • .NET Core 2.1
  • Visual Studio 2017

インターフェイスと実装クラス

以下のような2つのインターフェイスがあったとします。

interface IFoo
{
    string GetFoo();
}
interface IBar
{
    string GetBar();
}

この2つのインターフェイスを以下のように実装したとします。

class ImplClass : IFoo, IBar
{
    public ImplClass()
    {
        var guid = Guid.NewGuid();
        Console.WriteLine($"GUID={guid}");
    }

    public string GetFoo() => "Foo";
    public string GetBar() => "Bar";
}

この ImplClass を以下のように IFoo IBar として DI する場合を考えてみます。

class Class1
{
    public Class1(IFoo foo)
    {
        Console.WriteLine(foo.GetFoo());
    }
}
class Class2
{
    public Class2(IBar bar)
    {
        Console.WriteLine(bar.GetBar());
    }
}

異なる実体での DI

この場合は簡単です。
以下のように、ImplClassIFoo IBar としてそれぞれ登録します。

static void Main(string[] args)
{
    IServiceCollection services = new ServiceCollection();

    services.AddSingleton<IFoo, ImplClass>();
    services.AddSingleton<IBar, ImplClass>();
    services.AddSingleton<Class1>();
    services.AddSingleton<Class2>();

    IServiceProvider serviceProvider = services.BuildServiceProvider();

    serviceProvider.GetService<Class1>();
    serviceProvider.GetService<Class2>();

    Console.ReadKey();
}

実行結果

GUID=83b231eb-49db-4e5a-bfea-0e3d0c6f369e
Foo
GUID=175790cf-0382-4482-a9a0-69baf900424c
Bar

GUID を見てわかるように実体は異なります。

実体は1つだけど、異なる型で DI する場合

この場合、少し工夫が必要です。
以下のように、先に ImplClass を登録した上で、IFooIBar の登録時には ImplClass の実体を IServiceProvider から取得します。

static void Main(string[] args)
{
    IServiceCollection services = new ServiceCollection();

    services.AddSingleton<ImplClass>();
    services.AddSingleton<IFoo>(x => x.GetService<ImplClass>());
    services.AddSingleton<IBar>(x => x.GetService<ImplClass>());
    services.AddSingleton<Class1>();
    services.AddSingleton<Class2>();

    IServiceProvider serviceProvider = services.BuildServiceProvider();

    serviceProvider.GetService<Class1>();
    serviceProvider.GetService<Class2>();

    Console.ReadKey();
}

実行結果

GUID=26dd36ef-7cc9-4001-a591-5b229c2edd48
Foo
Bar

ImplClass のコンストラクタが一回しか呼ばれておらず、実体が1つであることがわかります。