Castle Windsor: Register class with internal constructor?

旧城冷巷雨未停 提交于 2019-12-20 01:46:35

问题


A Castle Windsor question: Is it possible to register a class that has an internal constructor with the container?

Thanks Joni


回答1:


Yes, it is possible. Default component activator looks only for public constructors. You can either provide custom component activator for that component that would take internal constructor into account, or use for example factory to activate the component:

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

However you should really reconsider making the .ctor internal in the first place. It is really rarely a good idea to do so, especially when you're exposing the class as a component to the outside world anyway.




回答2:


Following the accepted answer's advice, I was able to extend the DefaultComponentActivator class to work with protected constructors (it still does not work with private or internal; the code below works fine, that is, but something else in the DynamicProxy creation chain fails).

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

Then, on your container you register this against a ComponentRegistration object via the generic Activator method, so my container.Register call looks something like this:

    _container.Register
    (
        // . . .

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

        // . . .
    );

Hope that helps someone!




回答3:


It is easier to avoid the issue by having the class be internal and its constructor public, then you can register it with IncludeNonPublicTypes().

// All other classes
Classes.FromThisAssembly()
.IncludeNonPublicTypes()  // Internal types
.Where(x => !x.IsAbstract)
.Configure(x => x.Named(Guid.NewGuid().ToString()))


来源:https://stackoverflow.com/questions/2370546/castle-windsor-register-class-with-internal-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!