Dependency injection 具有开放通用接口的Windsor类型工厂

Dependency injection 具有开放通用接口的Windsor类型工厂,dependency-injection,castle-windsor,factory-pattern,Dependency Injection,Castle Windsor,Factory Pattern,在我的应用程序中,我希望在一个类中获取对多个存储库的依赖关系,而不是每次都需要所有存储库。我使用Windsor中的 然而,为每个存储库注册工厂有点烦人,我想用一个开放的通用注册来代替它。我想做的事情如下: container.Register( Component.For<IFactory<IRepository<>>>().AsFactory() ); container.Register( Component.For().AsFactory()

在我的应用程序中,我希望在一个类中获取对多个存储库的依赖关系,而不是每次都需要所有存储库。我使用Windsor中的

然而,为每个存储库注册工厂有点烦人,我想用一个开放的通用注册来代替它。我想做的事情如下:

container.Register(
    Component.For<IFactory<IRepository<>>>().AsFactory()
);
container.Register(
Component.For().AsFactory()
);
但是,这是一个语法错误,因为缺少IRepository的类型参数。有没有一种语法可以让我使用

注意:我知道我可以注册一个非类型化的工厂接口,并使用它来创建多个组件。我对这样做不感兴趣,因为这本质上是对服务定位器的依赖-如果我没有注册依赖,那么直到代码尝试使用它之前我不会知道它-通过我的方法,我在构造函数中知道这一点,即使我还没有创建实例

完整(简化)样本如下:

public class TestA { }
public class TestB { }
public interface IRepository<T> { T Create();    }
public class Repository<T> : IRepository<T>
{
    public T Create() { return Activator.CreateInstance<T>(); }
}

public interface IFactory<T>
{
    T Create();
    void Release(T instance);
}

class Program
{
    static void Main(string[] args)
    {
        IWindsorContainer container = new WindsorContainer();
        container.AddFacility<TypedFactoryFacility>();

        container.Register(
            // Individual registrations of repositories here are fine
            Component.For<IRepository<TestA>>().ImplementedBy<Repository<TestA>>(),
            Component.For<IRepository<TestB>>().ImplementedBy<Repository<TestB>>()
        );

        container.Register(
            // Individual registrations of factories - works, but trying to avoid!
            Component.For<IFactory<IRepository<TestA>>>().AsFactory(),
            Component.For<IFactory<IRepository<TestB>>>().AsFactory()
        );

        container.Register(
            // Generic Registration of Factories - syntax errors
            // Component.For<IFactory<IRepository<>>>().AsFactory()
            // Component.For(typeof(IFactory<IRepository<>>)).AsFactory()
        );

        var factoryA = container.Resolve<IFactory<IRepository<TestA>>>();
        var factoryB = container.Resolve<IFactory<IRepository<TestB>>>();

        var repoA = factoryA.Create();
        var repoB = factoryB.Create();

        Console.WriteLine("Everything worked");
    }
}
公共类TestA{}
公共类TestB{}
公共接口IRepository{T Create();}
公共类存储库:IRepository
{
public T Create(){return Activator.CreateInstance();}
}
公共接口工厂
{
T Create();
无效释放(T实例);
}
班级计划
{
静态void Main(字符串[]参数)
{
IWindsorContainer=新WindsorContainer();
container.AddFacility();
集装箱。登记(
//这里可以单独注册存储库
Component.For().ImplementedBy(),
Component.For().ImplementedBy()实现
);
集装箱。登记(
//工厂的个人注册-工作,但试图避免!
Component.For().AsFactory(),
Component.For().AsFactory()
);
集装箱。登记(
//工厂的通用注册-语法错误
//Component.For().AsFactory()
//组件.For(typeof(IFactory)).AsFactory()
);
var factoryA=container.Resolve();
var factoryB=container.Resolve();
var repoA=factoryA.Create();
var repoB=factoryB.Create();
Console.WriteLine(“一切正常”);
}
}

有一种将存储库分组的模式。它被称为。因此,与其创建用于创建存储库的工厂,不如创建一个引用这些存储库的工作类单元。例如:

公共抽象类UnitOfWork:IDisposable
{
//这是你们的工厂
受保护的抽象IRepository GetRepository();
公共IRepository用户
{
获取{返回这个.GetRepository();
}
公共电子储蓄客户
{
获取{返回这个.GetRepository();
}
//等等。。
}
在中,您可以定义一个
UnitOfWork
实现,该实现包含对Windsor的引用,并使您能够获取
IRepository
实现:

内部密封类WindsorUnitOfWork:UnitOfWork
{
私人温莎集装箱;
公共WindsorUnitOfWork(WindsorContainer容器)
{
this.container=容器;
}
受保护的覆盖IRepository GetRepository()
{
返回此.container.Resolve();
}
}
并登记如下:

public interface IRepositoryFactory<T>
{
    IRepository<T> Create();
    void Release(IRepository<T> instance);
}
container.Register(Component.For())
.由()实施
(生活方式,短暂),;
消费者现在有了一种非常方便的使用存储库的方法:

专用只读UnitOfWork数据库;
公共服务(UnitOfWork db)
{
这个.db=db;
}
public int CalculateArmaforActivityUsersByName(字符串名称)
{
变量用户=
来自this.db.Users中的用户
其中user.Name==Name
其中user.Active
选择用户;
返回users.Sum(user=>user.Karma);
}

您的factory接口定义有点太“开放”。请按如下方式更改factory接口:

public interface IRepositoryFactory<T>
{
    IRepository<T> Create();
    void Release(IRepository<T> instance);
}
公共接口IRepositoryFactory
{
i假定创建();
无效释放(假定实例);
}
然后您可以注册:

container.Register(Component.For(typeof(IRepositoryFactory<>)).AsFactory());
container.Register(Component.For(typeof(IRepositoryFactory)).AsFactory();
并决心:

var factoryA = container.Resolve<IRepositoryFactory<TestA>>();
var factoryB = container.Resolve<IRepositoryFactory<TestB>>();
var factoryA=container.Resolve();
var factoryB=container.Resolve();

我知道UoW,但这不是我想要的。我特别想看看我是否可以在这里要求的类型化工厂上使用注册模式。如果有帮助的话,假装我的类不是IRepository-它们被选为与人们相关的东西。此外,你的
WindsorUoW
类仍然是essentia“我只是一个服务定位器,而未注册的存储库在有人尝试使用它们之前是不会被检测到的。@理查德:没有
iRepositoy
的上下文,我无法回答你的问题。我对温莎的了解并没有那么深。请注意,
WindsorUoW
绝对不是一个服务定位器,因为它是在你的组件中定义的。”根(或者至少应该是)。在这种情况下,它只是基础结构的一部分。它是一个基础结构组件。请看一下这个主题。重点是,在代码中,当您调用
CalculateArmaforActivityUsersByName
时,您将得到一个异常,因为您没有依赖IRepository(假设它没有注册,这正是我试图解决的问题)-你有一个类可以找到并创建它。在我看来(以及我对你的链接文章的阅读)仍然是服务定位器。如果您的UnitOfWork类依赖于repo而不是容器,则情况会有所不同。由于
GetRepository
方法返回特定类型的对象(存储库),而不是任何类型的对象,因此我们不能说服务定位器