IOCとDIの概要 IOC(Inversion of Control)とは、プログラムの上位層が下位層への依存を、第三者のコンテナに組み立てるために移すことです。これはプログラム設計の目標であり、実現方法には依存性注入(Dependency Injection)と依存性検索(Dependency Lookup)が含まれます(.NETでは依存性注入のみがサポートされています)。DI(Dependency Injection)は、IOCの実装方法です。
Unityコンテナの基本操作 Unityコンテナは、サービスの登録、解決、およびライフタイム管理を担当します。
サービス登録(Register):インターフェースとその実装クラスをマッピングし、オブジェクトのライフタイムポリシーを指定します。
サービス解決(Resolve):登録情報に基づいてサービスのインスタンスを作成し、返却します。
ライフタイム管理:指定されたライフタイム戦略に従ってオブジェクトインスタンスの作成、キャッシュ、破棄を管理します。
以下は、Unityコンテナを使用してサービスを登録し、解決する基本的な例です。
using System;
// サービスインターフェース
public interface IVehicle
{
void Start();
void Stop();
}
// サービスの実装クラス
public class ElectricCar : IVehicle
{
public void Start()
{
Console.WriteLine("電気自動車が起動しました。");
}
public void Stop()
{
Console.WriteLine("電気自動車が停止しました。");
}
}
class Program
{
static void Main(string[] args)
{
// Unityコンテナのインスタンスを作成
var unityContainer = new UnityContainer();
// インターフェースと実装クラスのマッピングを登録
unityContainer.RegisterType<IVehicle, ElectricCar>();
// サービスを解決してインスタンスを取得
var vehicle = unityContainer.Resolve<IVehicle>();
// メソッドを呼び出す
vehicle.Start();
vehicle.Stop();
Console.ReadKey();
}
}
ライフタイムマネージャ RegisterTypeメソッドでマッピングを登録する際に、LifetimeManagerを指定しない場合、デフォルトでTransientなLifetime Managerが使用されます。これは、コンテナからオブジェクトのインスタンスを取得するたびに、新しいインスタンスが作成されることを意味します。つまり、コンテナはそのオブジェクトへの参照を保持しません。
特定のコンストラクタへの依存性注入 コンストラクタにパラメータを注入する必要がある場合、UnityはParameterOverrideとParameterOverridesを使用してこれをサポートしています。ParameterOverrideは単一のパラメータを、ParameterOverridesはパラメータのリストを対象とします。
例えば、3つのパラメータを持つコンストラクタを登録し、Resolve時に2つのパラメータを置き換えることができます。以下に、パラメータの初期化とオーバーライドの完全なコードを示します。
using System;
using Unity;
// パラメータ付きコンストラクタを持つクラス
public class Engine
{
private readonly string _fuelType;
private readonly int _horsepower;
public Engine(string fuelType, int horsepower)
{
_fuelType = fuelType;
_horsepower = horsepower;
}
public void DisplayInfo()
{
Console.WriteLine($"燃料タイプ: {_fuelType}, 馬力: {_horsepower}hp");
}
}
class Program
{
static void Main(string[] args)
{
var unityContainer = new UnityContainer();
// パラメータのオーバーライドを定義
var overrides = new Unity.Resolution.ParameterOverrides();
overrides.Add("fuelType", "ハイブリッド");
overrides.Add("horsepower", 200);
// コンストラクタパラメータを指定して登録
unityContainer.RegisterType<Engine>(overrides.OnType<Engine>());
// サービスを解決
var engine = unityContainer.Resolve<Engine>();
engine.DisplayInfo();
Console.ReadKey();
}
}
設定ファイルからのコンテナ構成 Unityコンテナは、設定ファイル(app.configやweb.config)から構成情報を読み込むこともできます。これにより、コードから設定を分離し、柔軟性を高めることができます。
以下は、IUnityContainerをラップするヘルパークラスの例です。このクラスは、指定された構成ファイルからコンテナを設定し、サービスを解決するためのメソッドを提供します。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using Microsoft.Practices.Unity.Configuration;
using Unity;
public class UnityContainerManager
{
private readonly IUnityContainer _container;
public IUnityContainer Container => _container;
public UnityContainerManager()
{
_container = new UnityContainer();
LoadConfiguration();
}
private void LoadConfiguration()
{
var fileMap = new ExeConfigurationFileMap
{
ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "CfgFiles\\Unity.Config")
};
var configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
section.Configure(_container, "testContainer");
}
public T GetService<T>()
{
return _container.Resolve<T>();
}
public T GetService<T>(string configName)
{
return _container.Resolve<T>(configName);
}
public T GetService<T, M>(Dictionary<string, object> parameterList)
{
var overrides = new Unity.Resolution.ParameterOverrides();
foreach (var item in parameterList)
{
overrides.Add(item.Key, item.Value);
}
return _container.Resolve<T>(overrides.OnType<M>());
}
public T GetService<T, M>(string configName, Dictionary<string, object> parameterList)
{
var overrides = new Unity.Resolution.ParameterOverrides();
foreach (var item in parameterList)
{
overrides.Add(item.Key, item.Value);
}
return _container.Resolve<T>(configName, overrides);
}
}