使用Castle Windsor子容器来解析具有特定实例的类型

时间:2011-11-08 15:44:43

标签: dependency-injection castle-windsor

我目前正在使用Castle Windsor的子容器功能来覆盖特定类型在工厂方法中的特定实例的注册。我纯粹使用子容器,因此单个分辨率的注册是暂时的 - 换句话说,我不希望注册影响该类型的所有分辨率。

也许某些代码会解释我的意思。

我有一个Func充当工厂Func<IReportCategory, IReportCategoryViewModel> - 我给它一个IReportCategory的实现,它返回一个IReportCategoryViewModel的新实例。 (IReportCategoryViewModel依赖于IReportCategory)。

这是在Castle Windsor注册的,如下所示:

        container.Register(
            Component.For<Func<IReportCategory, IReportCategoryViewModel>>().Instance(
                category => ResolveCategoryViewModelFactory(container, category)));

ResolveCategoryViewModelFactory的实施方式如下:

    private CategoryViewModel ResolveCategoryViewModelFactory(IWindsorContainer container, IReportCategory category)
    {
        using (IWindsorContainer childContainer = new WindsorContainer())
        {
            childContainer.Register(Component.For<IReportCategory>().Instance(category));
            container.AddChildContainer(childContainer);

            return childContainer.Resolve<IReportCategoryViewModel>();
        }
    }

上述方法实现的是IReportCategoryViewModel的解析,将IReportCategory的特定实例作为依赖项注入。如果IReportCategoryViewModel具有其他需要满足的依赖项,那么这些依赖项将由容器自动注入。

我随后可以按如下方式使用Func:

public class Test
{
    private readonly Func<IReportCategory, IReportCategoryViewModel> factory;

    public Test(Func<IReportCategory, IReportCategoryViewModel> factory)
    {
        this.factory = factory;
    }

    public void ResolveTest()
    {
        // Create a category (note: this would probably be resolved from the container in some way)
        IReportCategory category = new ReportCategory();

        // Call into the factory to resolve the view model
        IReportCategoryViewModel vm = factory(category);
    }
    ...

问题:这看起来像是一件合适的事情吗?从我得到的印象中,温莎城堡不建议使用儿童容器 - 是否有另一种方法可以达到相同的效果?

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

遵循Krzysztof建议使用Typed Factories,以下是我实现上述功能的方法。它比使用子容器简单得多!

首先,创建一个工厂界面,定义工厂方法的签名:

public interface ICategoryViewModelFactory
{
    CategoryViewModel Create(ReportCategory category);
} 

接下来,确保在容器中启用TypedFactoryFacility

container.AddFacility<TypedFactoryFacility>();

最后,使用容器注册工厂界面:

container.Register(
    Component.For<ICategoryViewModelFactory>()
        .AsFactory());

现在您可以将ICategoryViewModelFactory注入您的课程,并调用Create()方法创建CategoryViewModel的新实例:

public class SomeClass
{
    public SomeClass(ICategoryViewModelFactory categoryViewModelFactory)
    {
        // This would probably be resolved by the container (it's like this for the example)
        ReportCategory category = new ReportCategory();

        // Get Windsor to resolve the view model using the factory
        ReportCategoryViewModel vm = categoryViewModelFactory.Create(category);

        ....

警告:工厂方法中的参数名称需要与工厂创建的对象的构造函数的参数名称匹配。在上面的示例中,工厂接口定义了方法:

CategoryViewModel Create(ReportCategory category)

CategoryViewModel的构造函数还必须具有名为“category”的参数:

public CategoryViewModel(ReportCategory category)

这是因为工厂方法等同于以下内容:

container.Resolve<CategoryViewModel>(new { category = paramPassedIntoFactoryMethod });

答案 1 :(得分:2)

绝对有更好的方法,你现在使用的代码有一个错误 - 当你处理子容器时它会尝试释放你正在解决的所有组件实例,因此它们可能无法使用(甚至在你有机会使用它们之前)。

如果我理解你的解释,感觉就像是typed factories的工作。