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 съдържа configuredParameters и configuredProperties в частните си полета. Можете да ги прочетете чрез 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