Замок Виндзор: Зарегистрировать класс с внутренним конструктором? - PullRequest
3 голосов
/ 03 марта 2010

Вопрос о Виндзорском замке: Можно ли зарегистрировать класс с внутренним конструктором в контейнере?

Спасибо Джони

Ответы [ 3 ]

6 голосов
/ 03 марта 2010

Да, это возможно. Активатор компонента по умолчанию ищет только общедоступные конструкторы. Вы можете либо предоставить пользовательский активатор компонента для этого компонента, который будет учитывать внутренний конструктор, либо использовать, например, фабрику для активации компонента:

var container = new WindsorContainer()
    .AddFacility<FactorySupportFacility>()
    .Register( Component.For<Foo>()
                   .UsingFactoryMethod( () => new Foo() ) );
var foo = container.Resolve<Foo>();

Однако вы должны действительно пересмотреть вопрос о том, чтобы сделать .ctor внутренним. Это действительно редко хорошая идея, особенно если вы все равно представляете класс как компонент внешнему миру.

0 голосов
/ 28 февраля 2019

Проще избежать этой проблемы, если класс будет внутренним, а его конструктор общедоступным, а затем зарегистрировать его с помощью IncludeNonPublicTypes ().

// All other classes
Classes.FromThisAssembly()
.IncludeNonPublicTypes()  // Internal types
.Where(x => !x.IsAbstract)
.Configure(x => x.Named(Guid.NewGuid().ToString()))
0 голосов
/ 28 июня 2014

Следуя совету принятого ответа, я смог расширить класс DefaultComponentActivator для работы с конструкторами protected (он по-прежнему не работает с private или internal; код ниже работает нормально, но что-то еще в цепочке создания DynamicProxy не работает).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Castle.Core;
using Castle.MicroKernel;
using Castle.MicroKernel.ComponentActivator;
using Castle.MicroKernel.Context;

namespace /* YourNameSpaceHere */
{
    [Serializable]
    public class NonPublicComponentActivator : DefaultComponentActivator
    {
        public NonPublicComponentActivator(ComponentModel model, IKernelInternal kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
            : base(model, kernel, onCreation, onDestruction)
        { /* do nothing */ }

        private readonly List<Type> loadedTypes = new List<Type>();
        protected override ConstructorCandidate SelectEligibleConstructor(CreationContext context)
        {
            lock (loadedTypes)
            {
                if (!loadedTypes.Contains(context.RequestedType))
                {
                    loadedTypes.Add(context.RequestedType);

                    // Add the missing non-public constructors too:
                    var ctors = context.RequestedType.GetConstructors
                    (
                        BindingFlags.NonPublic | BindingFlags.Instance
                    );

                    foreach (var ctor in ctors)
                    {
                        Model.AddConstructor
                        (
                            new ConstructorCandidate
                            (
                                ctor,
                                ctor.GetParameters().Select(pi => new ConstructorDependencyModel(pi)).ToArray()
                            )
                        );
                    }
                }
            }

            return base.SelectEligibleConstructor(context);
        }
    }
}

Затем в вашем контейнере вы регистрируете это для объекта ComponentRegistration с помощью общего метода Activator, поэтому мой вызов container.Register выглядит примерно так:

    _container.Register
    (
        // . . .

        AllClasses.FromThisAssembly().BasedOn<ISomeInterface>()
            .Configure
            (
                c => c.LifeStyle.Transient
                    .Interceptors<MyInterceptor>()
                    .Activator<NonPublicComponentActivator>() // <--- REGISTERED HERE
            ),

        // . . .
    );

Надеюсь, это кому-нибудь поможет!

...