VB.NET + Windows Forms + Unity.Container で Dependency Injection(依存性注入)
前置き
この記事はQiita Visual Basic Advent Calendar 2019 の11日目の記事です。
.NET Core 3.0 では WinForms が対応され、Visual Basic 16.0 (Visual Studio 2019) もリリースされました。
Visual Studio 2019 16.4 では、まだ .NET Core 3.1 + WinForms + Visual Basic のテンプレートは対応されていないようでしたが、
.NET Core 3系におけるVBの対応は前向きに進んでいるように見えるので、今後の展開に注目しています。
developercommunity.visualstudio.com
で(唐突)、Advent Calendar 用のネタが何か無いか探したところ、
「Adaptive Code」で読んだ Unitiy を利用した Dependency Injection を VB + WinForms で行えるか試してみることにしました。
はじめに
まず、以下のコードはForm1の中でrepository
のインスタンスをNewしているので、
Form1はrepository
に依存している関係にあります。
Public Class Form1 Private ReadOnly repository As New Repository Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MessageBox.Show(Join(repository.getAll.ToArray, ",")) End Sub End Class
Unitiy.Container を用いた依存性注入
ここから依存性注入の形に変えていくには、Repository
をIRepository
インターフェースで抽象化し、
コンストラクタの引数でインスタンスを渡す形に変更します。
Public Class Form1 Private ReadOnly repository As IRepository Sub New(repository As IRepository) ' この呼び出しはデザイナーで必要です。 InitializeComponent() ' InitializeComponent() 呼び出しの後で初期化を追加します。 Me.repository = repository End Sub Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click MessageBox.Show(Join(repository.getAll.ToArray, ",")) End Sub End Class
Public Interface IRepository Function getAll() As List(Of String) End Interface
Public Class Repository Implements IRepository Public Function getAll() As List(Of String) Implements IRepository.getAll Return New List(Of String) From {"1", "2", "3"} End Function End Class
NuGet でUnity.Container
をインストールします。
メインエントリポイントModule Program
を手動で追加して、
そこにコンテナの初期化とインターフェイスとインスタンス生成の紐付けを記述します。
名前空間Unity
のImportを忘れずに。
Imports Unity Public Module Program <STAThread()> Sub Main() Dim container As IUnityContainer = New UnityContainer container.RegisterInstance(Of IRepository)(New Repository()) Application.EnableVisualStyles() Application.SetCompatibleTextRenderingDefault(False) Application.Run(container.Resolve(Of Form1)) End Sub End Module
ポイントはcontainer.Resolve(Of Form1)
により、
Form1のコンストラクタSub New(repository As IRepository)
の引数repository
に
NewされたRepository
のインスタンスが渡されることです。
依存性をクラスの外側から注入できたことになります。
Unity.Configuration を使って、App.Config でインターフェイスとインスタンスを紐付け
ここからさらに、Unity.Configuration を使って、
App.Config でインターフェイスとインスタンスの紐付けを記述する形に変更します。
NuGetからUnity.Configuration
をインストールします。
インストール後、Program
モジュールで名前空間Microsoft.Practices.Unity.Configuration
をインポートします。
設定ファイルの値をContainerに読み込む拡張メソッドLoadConfiguration
がMicrosoft.Practices.Unity.Configuration
に存在するためです。
Imports Unity Imports Microsoft.Practices.Unity.Configuration Public Module Program <STAThread()> Sub Main() Dim container As IUnityContainer = New UnityContainer container.LoadConfiguration() Application.EnableVisualStyles() Application.SetCompatibleTextRenderingDefault(False) Application.Run(container.Resolve(Of Form1)) End Sub End Module
App.Config には以下を追加します。
<configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration" /> </configSections> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" /> </startup> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <assembly name="WindowsAppVb" /> <namespace name="WindowsAppVb" /> <container> <register type="IRepository" mapTo="Repository" /> </container> </unity>
※assembly name
も記述しないと実行時に
「The type name or alias ”xxxxx“ could not be resolved. Please check your configuration file and verify this type name.”」
が発生しました。
以上、「VB.NET + Windows Forms + Unity で Dependency Injection(依存性注入)」でした。
おわりに
VB.NETでWinForm、ASP.NET WebFormの保守開発をしているVBerの皆様、
いやいや、ていうかVB6.0の保守開発しているんですけど、というVBerの皆様、
良いお年を。来年も頑張りましょう。