view Implab.ServiceHost/Unity/FactoryElement.cs @ 279:8714471e8d78 v3

Container configuration cleanup, RC2
author cin
date Fri, 04 May 2018 18:12:42 +0300
parents 6691aff01de1
children e0916ddc9950
line wrap: on
line source

using System;
using System.Xml.Serialization;
using Implab.Components;

namespace Implab.ServiceHost.Unity {
    /// <summary>
    /// Расширяет стандартную регистрацию типа до фабрики, вместе с регистрацией
    /// самой фабрики создаются регистрации сервисов, которые она предоставляет.
    /// </summary>
    public class FactoryElement : RegisterElement, ITypeRegistration {

        /// <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
                    };
                    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);
            }
        }
    }
}