我已经阅读了很多关于IoC容器的主题,特别是Mark Seemann的博客文章,他强调了convention over configuration的重要性。我理解并同意他的观点,但我想知道如何最好地为一个不规律的一生做好课程?
例如,我的大多数服务都注册了Transient
生命周期 - 但我希望将特定服务注册为Singleton
,因为它会执行一些有用的缓存。
我已经考虑过使用一些自定义属性,但是我已经阅读了相反的参数(因为它将组合逻辑放在了类中)。
我对这些辩论也有过例如对配置原语的依赖性。最终我最终使用了参数属性,因为它适用于我的情况,但我觉得也许我没有看到“隐藏的危险”。
答案 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)); }