使用温莎城堡子容器解析具有特定实例的类型

发布于 2024-12-14 10:32:33 字数 1994 浏览 0 评论 0原文

我目前正在使用温莎城堡的子容器功能来覆盖工厂方法中特定实例对特定类型的注册。我纯粹使用子容器,以便注册对于单个分辨率来说是临时的 - 换句话说,我不希望注册影响该类型的所有分辨率。

也许一些代码可以解释我的意思。

我有一个充当工厂 Func 的 Func - 我给它一个 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);
    }
    ...

问题:这看起来合适吗?根据我的印象,温莎城堡不建议使用子容器 - 是否有其他方法可以达到相同的结果?

感谢您的帮助。

I'm currently using Castle Windsor's child container functionality to override the registration of a particular type with a specific instance in a factory method. I am using the child containers purely so that the registration is temporary for a single resolution - in other words, I don't want the registration to affect all resolutions for that type.

Perhaps some code will explain what I mean.

I have a Func which acts as a factory Func<IReportCategory, IReportCategoryViewModel> - I give it an implementation of an IReportCategory and it returns a new instance of an IReportCategoryViewModel. (IReportCategoryViewModel has a dependency on IReportCategory).

This is registered with Castle Windsor as follows:

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

Where ResolveCategoryViewModelFactory is implemented as follows:

    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>();
        }
    }

What the above method achieves is the resolution of IReportCategoryViewModel, injecting the specific instance of IReportCategory as a dependency. If IReportCategoryViewModel has other dependencies that need satisfying, then these get automatically injected by the container.

I can subsequently use the Func as follows:

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);
    }
    ...

Question: Does this seem like a suitable thing to do? From the impression I get, child containers are not recommended in Castle Windsor - is there another way of achieving the same result?

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

东风软 2024-12-21 10:32:33

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

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

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 });

Following Krzysztof's advice to use Typed Factories, here is how I implemented the above functionality. It is far more simpler than using child containers!

Firstly, create a factory interface which defines the signature of the factory method:

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

Next, ensure the TypedFactoryFacility is enabled in the container:

container.AddFacility<TypedFactoryFacility>();

Finally, register the factory interface with the container:

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

Now you can inject ICategoryViewModelFactory into your classes, and call the Create() method to create a new instance of 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);

        ....

Warning: The parameter name in the factory method needs to match the parameter name of the constructor of the object the factory creates. In the above example, the factory interface defines the method:

CategoryViewModel Create(ReportCategory category)

The constructor for CategoryViewModel must also have the parameter named "category":

public CategoryViewModel(ReportCategory category)

This is because the factory method is the equivalent of the following:

container.Resolve<CategoryViewModel>(new { category = paramPassedIntoFactoryMethod });
遗心遗梦遗幸福 2024-12-21 10:32:33

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

如果我正确理解你的解释,感觉就像是类型化工厂的工作。

Absolutely there are better ways to go, and the code you're using right now has a bug - it will try to release all the component instances you're resolving when you dispose of the child container, therefore they might be unusable (disposed) before you even get a chance to use them.

If I understand your explanation correctly it feels like a job for typed factories.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文