C# 你为什么要用温莎作为工厂?

C# 你为什么要用温莎作为工厂?,c#,castle-windsor,C#,Castle Windsor,为什么要使用Castle Windsor factory的自动实现功能:AsFactory(),而不是请求所需的接口 例如: container.Register(Component.For<IEmailSender>().ImplementedBy<SmtpEmailSender>()); container.Register(Component.For<IEmailSenderFactory>().AsFactory().LifeStyle.Transie

为什么要使用Castle Windsor factory的自动实现功能:AsFactory(),而不是请求所需的接口

例如:

container.Register(Component.For<IEmailSender>().ImplementedBy<SmtpEmailSender>());
container.Register(Component.For<IEmailSenderFactory>().AsFactory().LifeStyle.Transient);
container.Register(Component.For().ImplementedBy());
container.Register(Component.For().AsFactory().LifeStyle.Transient);

使用(var factory=context.GetServiceFactory())
{
var emailSender=factory.CreateEmailSender();
emailSender.Send(message);
}
你为什么不干脆写:

var emailSender = context.GetServiceFactory<IEmailSender>();
emailSender.Send(message);
var-emailSender=context.GetServiceFactory();
emailSender.Send(message);
效果是一样的。Windsor将把IEmailSender解析为默认的注册实现,这有什么意义呢?

1。注入特定的构造函数参数 有时,当需要解析某个类时,您会编写一个需要特定值的类。例如:

public class NumberWriter : INumberWriter
{
    readonly int number;
    readonly IStream stream;

    public NumberWriter(int number, IStream stream)
    {
        this.number = number;
        this.stream = stream;
    }

    public Write()
    {
        stream.Write(number);
    }
}
如果没有
编号
,则无法解析此类的实例,并且可能还需要指定
(控制台、文件、打印机等)。因此,您定义了一个工厂:

public interface INumberWriterFactory
{
    INumberWriter Create(int number);
    INumberWriter Create(int number, IStream stream);
} 
现在,以下代码将起作用:

public class RandomNumberGenerator
{
    readonly INumberWriterFactory numberWriterFactory;

    public RandomNumberGenerator(INumberWriterFactory numberWriterFactory)
    {
        this.numberWriterFactory = numberWriterFactory;
    }

    public void Generate()
    {
         Random random = new Random();
         for (int i = 0; i < 10; i++)
         {
             // Writes to first IStream that Castle can resolve
             var numberWriter = numberWriterFactory.Create(random.Next());
             numberWriter.Write();
         }
    }

    public void Generate(IStream stream)
    {
         Random random = new Random();
         for (int i = 0; i < 10; i++)
         {
             // Writes to the given IStream
             var numberWriter = numberWriterFactory.Create(random.Next(), stream);
             numberWriter.Write();
         }
    }
}
RandomNumberGenerator
中没有变化,但行为发生了变化:

public class RandomNumberGenerator
{
    readonly INumberWriterFactory numberWriterFactory;

    public RandomNumberGenerator(INumberWriterFactory numberWriterFactory)
    {
        this.numberWriterFactory = numberWriterFactory;
    }

    public void Generate()
    {
         Random random = new Random();
         for (int i = 0; i < 10; i++)
         {
             // Writes to the IStream instance that the factory contains
             var numberWriter = numberWriterFactory.Create(random.Next());
             numberWriter.Write();
         }
    }  

    // the rest as before
}
公共类RandomNumberGenerator
{
只读INumberWriterFactory numberWriterFactory;
公共随机数生成器(INumberWriterFactory numberWriterFactory)
{
this.numberWriterFactory=numberWriterFactory;
}
public void Generate()
{
随机=新随机();
对于(int i=0;i<10;i++)
{
//写入工厂包含的IStream实例
var numberWriter=numberWriterFactory.Create(random.Next());
numberWriter.Write();
}
}  
//其余的和以前一样
}
同样,如果您已经在使用工厂接口,例如使用
AsFactory()
实现的工厂接口,则可以轻松地将其替换为新的实现,这一点非常有用。如果您已经在使用容器,那么执行此操作将更加困难;很难找到需要更改的位置,也很难将容器的用途换成新类型(即工厂)

注意:您必须创建一个
INumberWriterFactoryFactory
来将
IStream
注入到具体的工厂中

3.在合成根目录中保留IOC容器的使用 有很多人赞同只有一个容器的观点,这是唯一一次允许引用IOC容器。这样做可以帮助您避免几种反模式,例如模式


请注意,这些示例都是愚蠢的,但我希望它们能理解要点。

这里什么是
context.GetServiceFactory()
?只是一个用于解析类型的容器包装器?它是AppFabric CodeActivity的一部分。这不相关。您也可以从构造函数中的参数获取IEmailSenderFactory,但我所使用的代码很简单。是的,context.GetServiceFactory()只是容器解析的包装器。这些要点都得到了适当的注意;v清晰而详尽的答案!我想补充一些关于在工厂中替换组件解析机制的能力,但这只是噪音,所以我将+1你的回答我真的很喜欢这个答案,但在经历了一点痛苦之后,试图让参数化工厂工作,我发现了这个问题:。这似乎直接与您在第1点中描述的有用行为相矛盾。factory接口被解析一次,然后使用从第一次调用到factory函数的参数种子实现。是不是有什么我不明白的东西让我如此痛苦?
public class NumberWriterFactory : INumberWriterFactory
{
    readonly IStream stream;
    readonly IContainer container;

    public NumberWriterFactory(IStream stream, IContainer container)
    {
        this.stream = stream;
        this.container = container;
    }

    public INumberWriter Create(int number)
    {
        return container.Resolve<INumberWriter>(number, this.stream);
    }

    public INumberWriter Create(int number, IStream stream)
    {
        return container.Resolve<INumberWriter>(number, stream);
    }
}
public class RandomNumberGenerator
{
    readonly INumberWriterFactory numberWriterFactory;

    public RandomNumberGenerator(INumberWriterFactory numberWriterFactory)
    {
        this.numberWriterFactory = numberWriterFactory;
    }

    public void Generate()
    {
         Random random = new Random();
         for (int i = 0; i < 10; i++)
         {
             // Writes to the IStream instance that the factory contains
             var numberWriter = numberWriterFactory.Create(random.Next());
             numberWriter.Write();
         }
    }  

    // the rest as before
}