При регистрации класса или объекта в контейнере можно указать объект LifetimeManager, который будет управлять временем жизни экземпляров в контейнере.
Класс LifetimeManager очень простой, в нем всего три метода GetValue, SetValue и RemoveValue, причем последний не используется.
При помещении объекта в контейнер вызывается метод SetValue, а при необходимости получить объект вызывается GetValue и если он вернул null, то создается новый объект.
В библиотеку Microsoft.Practices.Unity входит несколько менеджеров.
TransientLifetimeManager – ничего не сохраняет, GetValue всегда возвращает null, поэтому объект создается каждый раз. Этот менеджер используется по-умолчанию при вызове RegisterType.
ContainerControlledLifetimeManager – сохраняет объект в локальной переменной. Поэтому объект живет столько же, сколько и контейнер. Этот (вернее другой, но с таким же поведением) менеджер используется по-умолчанию при вызове RegisterInstance.
ExternallyControlledLifetimeManager – сохраняет слабую ссылку (WeakReference) на объект. При использовании этого менеджера и вызове RegisterInstance сам вызывающий код должен управлять временем жизни объекта, помещенного в контейнер. Когда используется RegisterType этот менеджер будет выдавать уже существующий экземпляр объекта если он есть.
PerThreadLifetimeManager – сохраняет объекты в ThreadStatic словаре. Таким образом каждый поток в программе будет использовать свой набор объектов.
Для применения Unity в ASP.NET приложениях очень легко реализовать LifetimeManager, который сохраняет объект в контексте или в сессии.
Другие области применения LifetimeManager
В Unity нет возможности регистрации метода создания объектов, но это очень легко исправить с помощью своего LifetimeManager и пары extension-методов.
public class FactoryLifetimeManager<T>: LifetimeManager
{
Func<T> _factoryMethod;
LifetimeManager _baseManager;
public FactoryLifetimeManager(Func<T> factoryMethod, LifetimeManager baseManager)
{
_factoryMethod = factoryMethod;
_baseManager = baseManager;
}
public override object GetValue()
{
var obj = _baseManager.GetValue();
if (obj == null)
{
obj = _factoryMethod();
SetValue(obj);
}
return obj;
}
public override void RemoveValue()
{
_baseManager.RemoveValue();
}
public override void SetValue(object newValue)
{
_baseManager.SetValue(newValue);
}
}
public static class UnityFactoryMethodExtensions
{
public static IUnityContainer RegisterFactory<T>(this IUnityContainer container, Func<T> factoryMethod)
{
return container.RegisterFactory<T>(factoryMethod, new TransientLifetimeManager());
}
public static IUnityContainer RegisterFactory<T>(this IUnityContainer container, Func<T> factoryMethod, LifetimeManager lifetimeManager)
{
return container.RegisterType<T>(new FactoryLifetimeManager<T>(factoryMethod, lifetimeManager));
}
public static IUnityContainer RegisterFactory<T>(this IUnityContainer container, Func<T> factoryMethod, string name)
{
return container.RegisterFactory<T>(factoryMethod, name, new TransientLifetimeManager());
}
public static IUnityContainer RegisterFactory<T>(this IUnityContainer container, Func<T> factoryMethod, string name, LifetimeManager lifetimeManager)
{
return container.RegisterType<T>(name, new FactoryLifetimeManager<T>(factoryMethod, lifetimeManager));
}
}
