【问题标题】:Delayed/Lazy resolve延迟/懒惰的解决
【发布时间】:2011-10-04 16:56:33
【问题描述】:

给定以下代码:

public interface IMyContext
{
    string subtype { get; set; }
}

public class MyContext : IMyContext
{
    public string subtype { get; set; }
}

public interface IMyExporter
{
    string Export();
}

public class MyExporterXML : IMyExporter
{
    public string Export()
    {
        return "";
    }
}

public class MyExporterJson : IMyExporter
{
    public string Export()
    {
        return "";
    }
}

public class MyExporterFactory
{
    private IMyContext context;
    public MyExporterFactory(IMyContext context)
    {
        this.context = context;
    }

    public IMyExporter Create()
    {
        switch (context.subtype)
        {
            case "JSON" :
                    return new MyExporterJson();
            default:
                    return new MyExporterXML();
        }
    }
}

public class MyService
{
    private IMyContext context;
    private IMyExporter exporter;
    public MyService(IMyContext context, IMyExporter exporter)
    {
        this.context = context;
        this.exporter = exporter;
    }

    public string Extractdata()
    {
        return exporter.Export();
    }
}

[TestClass]
public class UnitTest2
{
    [TestMethod]
    public void TestMethod1()
    {
        var container = new WindsorContainer();
        container.Register(Component.For<IMyContext>().ImplementedBy<MyContext>());
        container.Register(Component.For<MyExporterFactory>());
        container.Register(Component.For<MyService>());
        container.Register(Component.For<IMyExporter>().UsingFactoryMethod(kernel => kernel.Resolve<MyExporterFactory>().Create()));
        var context = container.Resolve<IMyContext>();
        var service = container.Resolve<MyService>();

        context.subtype = "JSON";

        service.Extractdata();

    }
}

有没有办法让 MyService 中注入的导出器在实际使用时解析? IE。运行上述代码时,导出器解析为 MyExporterXML,但由于 context.subtype = "JSON" 设置,我真的希望它是 MyExporterJson。但是导出器在设置子类型之前就被解析了...

我知道 Castle::Windsor 有一种叫做基于委托的工厂,但我就是不知道如何使用它....

任何帮助将不胜感激,TIA

索伦

【问题讨论】:

    标签: castle-windsor lazy-evaluation resolve


    【解决方案1】:

    结合使用 TypeFactoryFacility 和自定义 ITypedFactoryComponentSelector。这应该适用于您的情况。

    首先,为工厂创建一个接口:

    public interface IMyExporterFactory
    {
        IMyExporter GetExporter(IMyContext context);
    }
    

    接下来,使用自定义的工厂组件选择器,它将使用上下文的子类型来确定组件名称(并更改注册以命名您的导出器):

    public class ExporterComponentSelector : DefaultTypedFactoryComponentSelector
    {
        protected override string GetComponentName(MethodInfo method, object[] arguments)
        {
            if (method.Name == "GetExporter")
            {
                var context = (IMyContext) arguments[0];
                return context.subtype;
            }
    
            return base.GetComponentName(method, arguments);
        }
    }
    

    以下是 Windsor 注册代码的更新,其中包括 TypedFactoryFacility 和自定义选择器(它根据导出器的子类型命名导出器):

    var container = new WindsorContainer();
    container.AddFacility<TypedFactoryFacility>();
    container.Register(
        Component.For<IMyExporterFactory>().AsFactory(c => c.SelectedWith(new ExporterComponentSelector())),
        Component.For<IMyExporter>().ImplementedBy<MyExporterJson>().Named("json"),
        Component.For<IMyExporter>().ImplementedBy<MyExporterXML>().Named("xml"),
        Component.For<IMyContext>().ImplementedBy<MyContext>(),
        Component.For<MyService>()
        );
    

    现在您的服务只需接收一个 IMyExporterFactory 并使用它来解析导出器:

    public class MyService
    {
        private readonly IMyContext context;
        private readonly IMyExporterFactory exporterFactory;
    
        public MyService(IMyContext context, IMyExporterFactory exporterFactory)
        {
            this.context = context;
            this.exporterFactory = exporterFactory;
        }
    
        public string Extractdata()
        {
            var exporter = exporterFactory.GetExporter(context);
            return exporter.Export();
        }
    }
    

    您可能希望确保如果组件注册时使用小写名称(“xml”、“json”),那么您的代码始终使用小写名称(或在 ExporterComponentSelector 中使用 context.subtype.ToLower())。

    【讨论】:

    • 是的,但我真正想要的是将正确的 Exporter 注入 MyService....
    • 为什么一定要注入?为什么不能使用工厂?老实说,在这种情况下,使用工厂更健壮一些。如果“MyService”类在您调用 Extractdata 之前更改了 context.subtype(出于某种原因),您仍然会拥有来自 ctor 的导出器。通过使用工厂进行解析,您可以确保在调用 Extractdata() 时始终根据上下文的子类型使用正确的导出器。
    • 它不必注入,隐藏这种延迟的依赖关系会非常好,因为编写服务的开发人员不知道选择一个或其他导出器,他只需要知道有一个并且可以使用它。只是认为有一种方法可以根据延迟依赖来控制解决的问题。
    • +1 这个问题几乎就是我的问题,而且解决方案非常简单,让我眼前一亮!谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多