Autofac: переопределение типа цели регистрации из модуля

Я хочу создать Autofac Module, который переопределяет тип цели регистрации на основе определенных критериев. Однако новый тип будет иметь тот же конструктор и должен быть создан с использованием тех же переопределений параметров, что и исходный тип.

Я могу использовать AttachToComponentRegistration, чтобы решить, следует ли переопределить регистрацию, но само переопределение создает проблему. Я предполагаю, что мне нужно заменить IInstanceActivator (конкретно ReflectionActivator), но я не вижу способа получить полную информацию о существующих ReflectionActivator — например, нет свойства для получения настроенных параметров.

Пример (упрощенный код):

protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry, IComponentRegistration registration) {
    base.AttachToComponentRegistration(componentRegistry, registration);
    var reflectionActivator = ((ComponentRegistration)registration).Activator as ReflectionActivator;
    if (reflectionActivator == null)
        return;

    var replacementType = ReplaceType(reflectionActivator.LimitType);
    if (replacementType == reflectionActivator.LimitType)
        return;

    ((ComponentRegistration)registration).Activator = new ReflectionActivator(
         replacementType,
         reflectionActivator.ConstructorFinder,
         reflectionActivator.ConstructorSelector,
         configuredParameters: ???, // how to get this?
         configuredProperties: ???  // or this?
    );
}

Это то, что можно сделать проще, и я просто что-то упустил?


person Andrey Shchekin    schedule 15.10.2013    source источник
comment
Почему бы вам просто не отменить регистрацию в вашей модели? Итак, builder.Register<MyNewType>.As<IMyInterface>, потому что, если вы не укажете модификатор .PreserveExistingDefaults(), Autofac просто переопределит предыдущую регистрацию.   -  person nemesv    schedule 15.10.2013
comment
@nemesv Я, наверное, немного не понимаю — я хочу заменить определенные целевые типы другим (динамически сгенерированным) типом с тем же конструктором. В вашем подходе я должен либо знать все типы статически заранее (у меня нет), либо иметь способ узнать параметры регистрации для перестроения регистрации (что возвращает к моему исходному вопросу).   -  person Andrey Shchekin    schedule 15.10.2013
comment
@AndreyShchekin Трудно получить то, что вы хотите сделать, не могли бы вы опубликовать пример кода, пожалуйста.   -  person Alexandr Nikitin    schedule 17.10.2013
comment
@AlexandrNikitin Я добавил пример кода.   -  person Andrey Shchekin    schedule 23.10.2013


Ответы (1)


ReflectionActivator содержит сконфигурированные параметры и сконфигурированные свойства в своих закрытых полях. Вы можете прочитать их через Reflection

var configuredParameters = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredParameters", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator);

var configuredProperties = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredProperties", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator);

И рабочий пример:

class Program
{
    interface IInterface
    {
    }

    class MyClass : IInterface
    {
        private readonly string _name;

        public MyClass(string name)
        {
            _name = name;
        }

        protected MyClass()
        {
        }

        public override string ToString()
        {
            return string.Format("{0} {1}", GetType(), _name);
        }
    }

    class MyReplacementClass : MyClass
    {
        private readonly string _name;

        public MyReplacementClass(string name)
        {
            _name = name;
        }

        public override string ToString()
        {
            return string.Format("{0} {1}", GetType(), _name);
        }
    }

    class MyModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<MyClass>().As<IInterface>().WithParameter("name", "Parameter");
        }

        protected override void AttachToComponentRegistration(IComponentRegistry componentRegistry,
            IComponentRegistration registration)
        {
            var reflectionActivator = ((ComponentRegistration) registration).Activator as ReflectionActivator;
            if (reflectionActivator == null)
                return;

            var replacementType = ReplaceType(reflectionActivator.LimitType);
            if (replacementType == reflectionActivator.LimitType)
                return;

            var configuredParameters = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredParameters",
                BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator);

            var configuredProperties = (IEnumerable<Parameter>)typeof(ReflectionActivator).GetField("_configuredProperties",
                BindingFlags.NonPublic | BindingFlags.Instance).GetValue(reflectionActivator);

            ((ComponentRegistration) registration).Activator = new ReflectionActivator(
                replacementType,
                reflectionActivator.ConstructorFinder,
                reflectionActivator.ConstructorSelector,
                configuredParameters,
                configuredProperties
                );
        }

        private Type ReplaceType(Type limitType)
        {
            return typeof (MyReplacementClass);
        }
    }

    static void Main(string[] args)
    {
        var builer = new ContainerBuilder();
        builer.RegisterModule<MyModule>();

        using (var container = builer.Build())
        {
            var myClass = container.Resolve<IInterface>();
            Console.WriteLine(myClass);
            Console.ReadKey();
        }
    }
}
person Alexandr Nikitin    schedule 23.10.2013
comment
Спасибо. К сожалению, мне придется отправить вопрос в Autofac, если я продолжу сторонний проект, который требует этого. Но это верный ответ. - person Andrey Shchekin; 30.10.2013