使用基于约定的注册时如何表示组件的生命周期?

时间:2013-11-12 13:46:06

标签: dependency-injection inversion-of-control ioc-container

我已经阅读了很多关于IoC容器的主题,特别是Mark Seemann的博客文章,他强调了convention over configuration的重要性。我理解并同意他的观点,但我想知道如何最好地为一个不规律的一生做好课程?

例如,我的大多数服务都注册了Transient生命周期 - 但我希望将特定服务注册为Singleton,因为它会执行一些有用的缓存。

我已经考虑过使用一些自定义属性,但是我已经阅读了相反的参数(因为它将组合逻辑放在了类中)。

我对这些辩论也有过例如对配置原语的依赖性。最终我最终使用了参数属性,因为它适用于我的情况,但我觉得也许我没有看到“隐藏的危险”。

1 个答案:

答案 0 :(得分:2)

IoC容器通常允许您指定对象的生活方式。例如,SimpleInjector提供开箱即用的瞬态和单例(并且还允许用户创建自定义生活方式类)。使用SimpleInjector,它就像:

一样简单
container.Register<ISvc, Impl>(Lifestyle.Singleton);

container.Register<ISvc, Impl>(Lifestyle.Transient);

无需使用合成逻辑来污染您的类。

对于配置原语,通常的做法是将它们置于接口之后。例如,我将连接字符串放在IDatabaseConfiguration接口后面,其实现从web.config中读取值。然后我将该接口注入我的数据服务。

编辑:无视以上。保持它以使评论有意义。

以下内容实际上并没有回答这个问题,但它可以解决引发问题的问题。你说这个课程做了一些有用的缓存,这让我了解到它承担了额外的责任。因此,我建议您不要尝试将单个实现注册为单例,而是围绕该实现创建一个装饰器类。

container.RegisterDecorator(
    typeof(ICommandHandler<>), 
    typeof(CommandHandlerCacheDecorator<>), 
    Lifestyle.Transient, 
    x => { return /*some logic that looks for and 
                    finds that one class you want 
                    to decorate*/
         });

装饰器需要是瞬态的,因为它会对它装饰的命令有一个瞬态引用。但是,它可以访问一个单独的单例类(当然通过依赖注入)或处理实际缓存的缓存对象。

编辑:挑出一个类来装饰的例子。有很多选择取决于你想要的具体程度。再次使用SimpleInjector,但我确信其他容器也有自己的类似物。

//decorate a specific class
x => { return x.ImplementationType.FullName == "My.Commands.Web.SomeName"; }

//decorate all classes that share a certain namespace
x => { return x.ImplementationType.Namespace.EndsWith("Commands.Web"); }

//decorate all classes that implement the same interface
x => { return x.ImplementationType.IsInstanceOfType(typeof(ICouldCache)); }