Mercurial > pub > ImplabNet
diff Implab.ServiceHost/Unity/FactoryElement.cs @ 278:6691aff01de1 v3
Implab: added XmlDefaultSeializer (SerializersPool is now obsolete)
Implab.ServiceHost: rewritten TypeReference (added support for nested types), stable API
author | cin |
---|---|
date | Thu, 03 May 2018 09:59:44 +0300 |
parents | |
children | 8714471e8d78 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Implab.ServiceHost/Unity/FactoryElement.cs Thu May 03 09:59:44 2018 +0300 @@ -0,0 +1,72 @@ +using System; +using System.Xml.Serialization; +using Implab.Components; + +namespace Implab.ServiceHost.Unity { + /// <summary> + /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией + /// самой фабрики создаются регистрации сервисов, которые она предоставляет. + /// </summary> + public class FactoryElement : RegisterElement { + + /// <summary> + /// Записи о сервисах, которые создаются данной фабрикой. + /// </summary> + /// <remarks> + /// Сервисы, которые указаны в регистарциях они должны соответсвовать тому, + /// что фабрика возвращает, но это остается на откуп контейнера + /// </remarks> + [XmlElement("provides")] + public ProvidesElement[] Provides { get; set; } + + /// <summary> + /// Переопределяет стандарное поведение регистрации типа в контейнере, + /// дополняя его регистрацией фабричных методов для получения типов. + /// </summary> + /// <param name="builder">Объект для конфигурирования контейнера.</param> + 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 + }; + activator.Visit(builder); + } + } 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 + }; + + activator.Visit(builder); + } + } + } +} \ No newline at end of file