为什么Castle Windsor类型工厂在使用不同参数创建时返回相同的实例

时间:2016-06-13 13:55:57

标签: c# castle-windsor

在使用typed factory facility时,我希望以下内容生成两个单独的实例。

using System;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace ConsoleApplication
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new WindsorContainer();

            container.AddFacility<TypedFactoryFacility>();

            container.Register(Component
                .For<IFactory>()
                .AsFactory()
                .LifestyleSingleton());

            container.Register(Component
                .For<IImplementation>()
                .ImplementedBy<Implementation>()
                .LifestylePerThread());

            var factory = container.Resolve<IFactory>();
            var implementation1 = factory.Create(1);
            var implementation2 = factory.Create(2);

            Console.WriteLine(implementation1 == implementation2);//Returns true!
            Console.Read();
        }
    }

    public interface IFactory
    {
        IImplementation Create(int dependency);
    }

    public interface IImplementation
    {}

    public class Implementation : IImplementation
    {
        private readonly int _dependency;

        public Implementation(int dependency)
        {
            _dependency = dependency;
        }
    }
}

我还尝试使用参数作为引用类型来覆盖.Equals().GetHashCode()而不是int,但它没有区别。

我意识到我可以使用LifestyleTransient来解决这个问题,但如果我传入相同的参数,我实际上想要接收相同的实例。

2 个答案:

答案 0 :(得分:3)

您的期望不正确。

传递给工厂方法的参数是当且仅当容器中没有所需服务的组件时才用于构造新组件的详细信息。

您的第二个请求来自同一个线程,并且是针对相同的服务,因此Windsor正确地返回已经构建的那个。

虽然吉拉德的建议是可以遵循的,但你可能仍然发现自己“打架”容器并使事情变得比他们需要的更复杂。

我建议您接受Windsor中可用的机制,它完全依赖服务类型(接口)来区分服务。

问问自己两个不同的实例是什么,并反映了接口方面的差异。例如也许你应该有一个IBigImplementationISmallImplementation?然后可以在容器中注册和配置这些不同服务的实现;你得到你想要的所有汇集/重用;并且消耗代码仍然没有意识到并且与实现细节分离。

[RANT:虽然工厂允许更大的灵活性,但我通常认为将参数用于工厂方法作为代码气味。正如您所发现的,它需要消费者对服务实现的生命周期做出假设。它还意味着控制实现细节的杠杆和开关分散在代码库中,而不是在容器注册代码中集中管理。]

答案 1 :(得分:2)

根据我对Castle的了解,TypedFactoryFacility会根据工厂界面尝试解决类型问题。如果你有IImplementation Create(int dependency)这样的函数,那么它将尝试从内核中解析IImplementation类型的对象。这就是为什么当你在Singelton注册时,你会得到同一个。

您实际需要的是“TypedFactory”,它将返回一个不是由类型而是由您拥有的对象实例返回的实例。您可以做的是实现一个ITypedFactoryComponentSelector,它会尝试从kernelIImplementation解析您已经传递的int dependency,如果不存在则注册一个MediaMetadataRetriever mediaMetadataRetriever=new MediaMetadataRetriever(); //should be stored as an instance variable mediaMetadataRetriever.setDataSource(mVideo.getVideoUrl(Video.SD)); int time = videoView.getCurrentPosition()* 1000; //micro-to-milliseconds Bitmap bmFrame = mediaMetadataRetriever.getFrameAtTime(time); 在回来之前。

您可以在此处查看有关TypedFactory和实现您自己的ITypedFactoryComponentSelector的更深入见解:https://github.com/castleproject/Windsor/blob/master/docs/typed-factory-facility-interface-based.md

希望这有帮助