Windsor键入工厂以创建与父

时间:2015-11-10 16:13:37

标签: c# castle-windsor

我的Wpf应用程序有很多不同的视图模型,这些模型依赖于存储库和命令工厂,注册了与视图模型绑定的瞬态生活方式。使用类型化工厂创建命令,该工厂将始终创建新的依赖项实例。这可能是一个问题,因为当视图模型依赖于存储库时,ORM中的跟踪问题以及依赖于该存储库的命令。

因此我希望我的命令工厂使用与视图模型相同的存储库实例创建命令。

如何在不手动创建工厂的情况下通过容器解决这个问题?

编辑 - 可运行代码的示例

public class Service
{
    private readonly IRepository repository;
    private readonly ICommandFactory commandFactory;

    public Service(IRepository repository, ICommandFactory commandFactory)
    {
        this.repository = repository;
        this.commandFactory = commandFactory;
    }

    public void DoIt()
    {
        repository.SaveChanges();
        commandFactory.Create().Execute();
    }
}

public interface ICommandFactory
{
    ICommand Create();
}

public interface ICommand
{
    void Execute();
}

public class Command : ICommand
{
    private readonly IRepository repository;

    public Command(IRepository repository)
    {
        this.repository = repository;
    }

    public void Execute()
    {
        repository.SaveChanges();
    }
}

public interface IRepository
{
    void SaveChanges();
}

public class Repository : IRepository
{
    private static int i = 0;
    private int instanceNumber = 0;

    public Repository()
    {
        instanceNumber = i++;
        Console.WriteLine("Created repository nr: " + instanceNumber);
    }

    public void SaveChanges()
    {
        Console.WriteLine("Save changes for repository nr: " + instanceNumber);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var container = new WindsorContainer();
        container.AddFacility<TypedFactoryFacility>();
        container.Register(Component.For<Service>().LifestyleTransient());
        container.Register(Component.For<IRepository>().ImplementedBy<Repository>().LifestyleBoundTo<object>());
        container.Register(Component.For<ICommand>().ImplementedBy<Command>().LifestyleTransient());
        container.Register(Component.For<ICommandFactory>().AsFactory().LifestyleTransient());

        var service = container.Resolve<Service>();

        service.DoIt();
    }
}

1 个答案:

答案 0 :(得分:1)

当您对所有依赖项使用瞬态生活方式时,很明显您在Service和Command类中有不同的IRepository实例。您需要的是增加IRepository的生命周期,并可能将其绑定到您的服务的生命周期,这意味着在创建和处理Service实例时创建并处理IRepository的实例。

Castle Windsor拥有Bound生活方式:

  

图中的某个地方我们有两个视图模型,一个取决于另一个,它们都依赖于其他一些服务,比如一个存储库。您可能希望将存储库绑定到子图。换句话说,您可能希望最外层视图模型的整个子图(WelcomeScreenViewModel)共享存储库的同一实例,并在视图模型本身发布时释放存储库。

所以应该按照以下方式注册您的IRepository:

Container.Register(Component.For<IRepository>().ImplementedBy<Repository>().LifestyleBoundTo<Service>());

修改 上面的解决方案不起作用,因为ICommand绑定到ICommandFactory而不是Service。如果要手动解析服务实例,可以使用LifestyleScoped:

        container.AddFacility<TypedFactoryFacility>();
        container.Register(Component.For<Service>().LifestyleTransient());
        container.Register(Component.For<IRepository>().ImplementedBy<Repository>().LifestyleScoped());
        container.Register(Component.For<ICommand>().ImplementedBy<Command>().LifestyleTransient());
        container.Register(Component.For<ICommandFactory>().AsFactory().LifestyleTransient());

        using (container.BeginScope())
        {
            var service = container.Resolve<Service>();
            service.DoIt();
        }

在这种情况下,您的IRepository的范围是每个范围。

注意要使用container.BeginScope(),请添加using Castle.MicroKernel.Lifestyle;