using System;
using System.Xml.Serialization;
using Implab.Components;
namespace Implab.ServiceHost.Unity {
///
/// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией
/// самой фабрики создаются регистрации сервисов, которые она предоставляет.
///
public class FactoryElement : RegisterElement, ITypeRegistration {
///
/// Записи о сервисах, которые создаются данной фабрикой.
///
///
/// Сервисы, которые указаны в регистарциях они должны соответсвовать тому,
/// что фабрика возвращает, но это остается на откуп контейнера
///
[XmlElement("provides")]
public ProvidesElement[] Provides { get; set; }
///
/// Переопределяет стандарное поведение регистрации типа в контейнере,
/// дополняя его регистрацией фабричных методов для получения типов.
///
/// Объект для конфигурирования контейнера.
public override void Visit(ContainerBuilder builder) {
var factoryType = GetRegistrationType(builder.ResolveType);
base.Visit(builder);
if (Provides != null && Provides.Length > 0) {
// если регистрации явно заданы, используеися информация из них
foreach(var item in Provides) {
var activator = new FactoryActivator {
Name = item.RegistrationName,
RegistrationType = builder.ResolveType(item.RegistrationType),
FactoryName = Name,
FactoryType = factoryType,
Lifetime = item.Lifetime.GetLifetime(builder)
};
builder.Visit(activator);
}
} else {
// если регистрация явно не задана, в качестве сервиса для регистрации
// используется тип создаваемый фабрикой, который будет добавлен в контейнер
// с темже именем, что и сама фабрика (разные типы могут иметь одно имя для регистрации)
var providedType = (
factoryType.IsGenericType && factoryType.GetGenericTypeDefinition() == typeof(IFactory<>) ?
factoryType :
factoryType.GetInterface(typeof(IFactory<>).FullName)
)?
.GetGenericArguments()[0];
// не удалось определеить тип
if (providedType == null)
throw new ArgumentException("Failed to determine a type provided by the factory");
if (providedType.IsGenericParameter)
throw new ArgumentException("Can't register a generic type paramter as a service");
var activator = new FactoryActivator {
Name = Name,
RegistrationType = providedType,
FactoryName = Name,
FactoryType = factoryType
};
builder.Visit(activator);
}
}
}
}