Windows From アプリケーションでDI (Dependency Injection) を利用する

Windows From アプリケーションでDI (Dependency Injection) を利用するコードと例を紹介します。

DI (Dependency Injection) とは

コンストラクタのパラメーターにタイプの型を記述するだけで、インスタンス化されたオブジェクトがコンストラクタの引数に送り込まれる仕組みです。 利用する側からの視点では、参照するクラス側でインスタンス化する必要がないため、お手軽にオブジェクトを利用できます。

DI (Dependency Injection)の基本的な動作とコードはこちらの記事を参照してください。

Windows Formアプリケーションでの利用

一般的には、ASP.NETのアプリケーションで利用する機会が多いですが、Windows Formで利用する場合のコードを紹介します。

プログラム

.NET 5でWindows Formアプリケーションを作成します。

事前準備

プロジェクトに Microsoft.Extensions.DependencyInjection のパッケージをインストールします。
NuGet パッケージマネージャーでインストールするか、または、パッケージマネージャーコンソールで次のコマンドを実行します。
Install-Package Microsoft.Extensions.DependencyInjection 

UI

下図のフォームを作成します。ボタンとテキストボックスを配置します。

コード

下記のコードを記述します。
MyService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DIDemoSimpleCustom
{
  public interface IMyService
  {
    int calc(int a, int b);
  }

  public class MyService : IMyService
  {
    public int calc(int a, int b)
    {
      return (a - b) * (a + b);
    }
  }
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.Extensions.DependencyInjection;
//using Microsoft.Extensions.Logging;

namespace DIDemoSimpleCustom
{
  static class Program
  {
 
    /// <summary>
    ///  The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
      Application.SetHighDpiMode(HighDpiMode.SystemAware);
      Application.EnableVisualStyles();
      Application.SetCompatibleTextRenderingDefault(false);

      ServiceCollection services = new ServiceCollection();
      ConfigureServices(services);
      ServiceProvider serviceProvider = services.BuildServiceProvider();

      FormMain form = (FormMain)serviceProvider.GetRequiredService<FormMain>();
      Application.Run(form);
    }

    private static void ConfigureServices(ServiceCollection services)
    {
      services.AddSingleton<FormMain>();
      services.AddScoped<IMyService, MyService>();
    }
  }
}

フォームのコードです。[button1]のクリックイベントの実装が主です。
FormMain.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DIDemoSimpleCustom
{
  public partial class FormMain : Form
  {

    private IMyService _mService;

    public FormMain(IMyService mService)
    {
      InitializeComponent();
      _mService = mService;
    }

    private void button1_Click(object sender, EventArgs e)
    {
      int result = _mService.calc(8, 3);
      textBox1.Text = "Service Result:" + result.ToString();
    }
  }
}

解説

MyService.cs

はじめに、クラスに注入されるクラスを定義します。 注入されるクラスは抽象クラスとして定義する必要があるため、interface 文を利用して抽象クラスを定義します。
  public interface IMyService
  {
    int calc(int a, int b);
  }

続いて、抽象クラスに対する実装を記述します。先に定義した IMyService のインターフェイスを継承してクラスの実装をします。
今回のデモでは、calc メソッドを定義し、a,b 2つの値を受け取り計算をして結果を返すメソッドになっています。
  public class MyService : IMyService
  {
    public int calc(int a, int b)
    {
      return (a - b) * (a + b);
    }
  }

Program.cs

ServiceCollectionオブジェクトを作成します。作成したServiceCollectionオブジェクトを ConfigureServices() メソッドに渡し、 ServiceCollectionオブジェクトを設定します。
設定が終わったServiceCollectionオブジェクトの BuildServiceProvider() メソッドを実行し、ServiceProvider オブジェクトを取得します。
      ServiceCollection services = new ServiceCollection();
      ConfigureServices(services);
      ServiceProvider serviceProvider = services.BuildServiceProvider();

ConfigureServices() メソッドは下記のコードです。AddSigleton メソッドを呼び出しServiceCollectionオブジェクトにサービスを追加します。
    private static void ConfigureServices(ServiceCollection services)
    {
      services.AddSingleton<FormMain>();
      services.AddScoped<IMyService, MyService>();
    }

フォームのインスタンスは通常のアプリケーションの場合はFormMain form = new FormMain() のようにnew演算子を利用してインスタンスを作成しますが、 Dependency Injection(DI) の場合はServiceProvider オブジェクトの GetService() または、GetRequiredService() メソッドを呼び出してインスタンスを作成します。
作成したインスタンスは、Application.Run() メソッドに渡され、Windows Formアプリケーションを実行します。
      FormMain form = (FormMain)serviceProvider.GetRequiredService<FormMain>();
      Application.Run(form);

フォーム

コンストラクタから注入されるオブジェクトのインスタンスを保持するためのプライベート変数を定義します。
注入されるオブジェクトの実装は参照しないようにするため、変数型はインターフェースの型とします。
    private IMyService _mService;

コンストラクタに IMyService のパラメーターを追記します。フォームのインスタンスが作成されたタイミングで、 MyServiceクラスのインスタンスオブジェクトがコンストラクタに渡されます。 渡されたオブジェクトをクラスのメンバ変数_mService 変数で保持します。
    public FormMain(IMyService mService)
    {
      InitializeComponent();
      _mService = mService;
    }

ボタンのクリックイベントです。コンストラクタで渡された、MyServiceおぶっジェクトの calc() メソッドを呼び出し、 メソッドの戻り値を result変数に格納します。result変数の内容はテキストボックスに表示します。
    private void button1_Click(object sender, EventArgs e)
    {
      int result = _mService.calc(8, 3);
      textBox1.Text = "Service Result:" + result.ToString();
    }

実行結果

プロジェクトを実行します。
下図のウィンドウが表示されます。


[button1]をクリックします。テキストボックスにメッセージが表示されます。
フォームのクラスに注入された MyService クラスのcalc()メソッドが実行され、計算結果がテキストボックスに表示されていることも確認できます。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
作成日: 2021-08-14
Copyright © iPentec all rights reserverd.