前回に引き続き DI コンテナ Unity の利用についてです。
前回は基本的なものを記述したので、今回は注入されるインスタンスの生存期間がコンテナと同一となる ContainerControlledLifetimeManager を設定したときの動作について記述します。
生成した注入を行うインスタンスの生存期間がコンテナと同一となることを確認するために、コンソール アプリケーションの Main メソッドの中で、注入が行われる Sample クラスのインスタンス生成を2回行います。
プロジェクトの作成、NuGet から Unity を導入、IInjectedClass インターフェイス、InjectedClass クラスの作成までは前回と同様になります。
で、Sample クラスです。
using System;
namespace ContainerLifetimeUnityDi
{
public class Sample : IDisposable
{
public Sample(IInjectedClass injected)
{
_injected = injected;
}
private readonly IInjectedClass _injected;
public void SetValue(int number) => _injected.Number = number;
public int GetValue() => _injected.Number;
public void Dispose()
{
Console.WriteLine("Disposed Sample instance!");
}
}
}
前回は、void Dispose(bool disposing) メソッドの中で InjectedClass クラスの Dispose() メソッドを呼び出していましたが、今回は Sample クラスのインスタンスと InjectedClass クラスのインスタンスの生存期間が異なるので、InjectedClass クラスの Dispose() メソッドをここに記述することはできません。
次に Program クラスです。
using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ContainerLifetimeUnityDi
{
class Program
{
static void Main(string[] args)
{
using (var container = new UnityContainer())
{
// ライフタイムにコンテナ コントロールを設定
// (コンテナのライフサイクルとなる InjectedClass のインスタンスはコンテナの dispose 時に dispose される。)
container.RegisterType<IInjectedClass, InjectedClass>(new ContainerControlledLifetimeManager());
using (var sample = container.Resolve<Sample>())
{
Console.WriteLine($"Number: {sample.GetValue()}");
sample.SetValue(10);
}
using (var sample2 = container.Resolve<Sample>())
{
Console.WriteLine($"Number: {sample2.GetValue()}");
sample2.SetValue(20);
}
}
Console.WriteLine("Press any key...");
Console.ReadKey();
}
}
}
container.RegisterType<IInjectedClass, InjectedClass>(new ContainerControlledLifetimeManager()); で、引数に ContainerControlledLifetimeManager のインスタンスを渡すことで、注入される InjectedClass のインスタンスの生存期間をコンテナと同一に設定しています。
Sample クラスが IDisposable インターフェイスを実装しているので、Using で囲み、インスタンスを2回生成させ、1回目の生成時に InjectedClass の Number プロパティに 10を設定し、2回目の生成時にその値を読み出しています。生成、設定、読み出しが非同期に行われる場合には、排他制御などを考慮する必要がありますが、このプログラムではその必要がないので、単純に行っています(Unity.MVC では、UnityContainer のインスタンス生成に System.Lazy クラスを用いて、スレッドセーフな遅延初期化を行っています。Lazy クラスがスレッドセーフを保証するのは初期化部分のみで、クラスの説明にあるとおり「複数のスレッドが遅延初期化されるオブジェクトにアクセスできる場合、それのプロパティとメソッドをマルチスレッド アクセスに対して安全にする必要があります。」)。
また、コメントに書いていますが、生成した InjectedClass が IDisposable インターフェイスを実装していれば、コンテナの Dispose() メソッドが呼び出されるときに InjectedClass の Dispose() メソッドも呼び出されます。
このプログラムを実行したときのコンソール出力のスクリーンショットを示します。
次回は、コンテナの受け渡しと複数インスタンスの注入についてです。
「DI コンテナ Unity の利用(その2)」への2件のフィードバック