我想为多个服务注册一个单例组件,并根据在解析调用期间使用的服务来定义要使用的构造函数。
我尝试过:
_builder.RegisterType<TComponent>()
.As<IService1>()
.FindConstructorsWith(ConstructorFinder1)
.SingleInstance();
_builder.RegisterType<TComponent>()
.As<IService2>()
.FindConstructorsWith(ConstructorFinder2)
.SingleInstance();
但这会导致两个不同的“单例”实例,具体取决于所使用的服务。
所以我尝试了:
_builder.RegisterType<TComponent>()
.As<IService1>()
.FindConstructorsWith(ConstructorFinder1)
.As<IService2>()
.FindConstructorsWith(ConstructorFinder2)
.SingleInstance();
这解决了单例问题,但遗憾的是第二个FindConstructorsWith
调用会覆盖第一个调用,即两个服务都ConstructorFinder2
被使用。
我曾经(希望)将针对服务存储ConstructorFinder,但显然并非如此。
我要实现的概念上是错误的,Autofac是否不支持它,或者我只是缺少某些东西?
编辑: 再次感谢特拉维斯的出色回应。显然我遗漏了一些细节,使事情变得混乱。让我现在添加一些。
这个问题实际上是对How to determine which constructor Autofac uses when resolving的一种跟进(Travis也帮助了我)。因此,反序列化时会出现问题,并且会影响许多不同的对象。
我得到有关组成,关注点分离以及如何将多个ctor经常视为代码气味的争论,但是在反序列化的情况下(至少对于我正在开发的应用程序而言),能够根据实例文件是新建的还是从项目文件反序列化的,以不同的方式创建实例。在反序列化时,不必初始化构建新实例时需要初始化的几个成员(因为反序列化期间它们的值都会被覆盖)。这将意味着额外的性能成本,并且(在这种情况下)会导致其他与一次性初始化有关的问题。
花了数天时间试图找到解决方案后(Newtonsoft Json方面也遇到了麻烦),我决定停止Autofac并实现我们自己的IOC容器。出于一般目的,它不能(显然!)以任何方式与Autofac竞争,但是由于我们实际上只使用了Autofac强大功能的一小部分,因此,我觉得我们可以尝试推出自己的产品。我花了很多时间才将头包裹在一个整体的黑匣子上。是的,Autofac是开源的,但是单步执行代码不会在公园里走动。
第一次测试非常有前途,重新获得对应用程序如此重要组成部分的完全控制感觉很好。
同样,离开Autofac的原因是无法(可行)根据构造单件组件的服务来定义其构造方式。从总体结构/概念的角度来看,我了解严格区分服务和构建方法是有意义的。但我相信,在反序列化期间,情况有所不同。而且,既然我已经独立于Autofac,我可能会决定更改机制,以使它们更直接地适应整个概念。
答案 0 :(得分:3)
这是一个很难回答的问题,因为似乎您有一些基本目标正在试图实现,并且您有想要解决的方案,但是也许这是错误的解决方案,您应该提出一个[新]问题取决于此响应对您的效果如何。
让我逐步了解一下是否可以解释为什么很难回答。
我想为多个服务注册一个单例组件,并根据在解析调用期间使用的服务来定义要使用的构造函数。
如果它是一个 singleton ,则表示整个系统中有一个 ,对吗?实际上,这将是“获胜第一”。如果某事物将其解析为IService1
,则将调用与之关联的构造函数,即使您尝试将其解析为IService2
,也不会发生任何构造,因为创建了单例。反之亦然-IService2
得到解析,并且遵循构造函数路径,然后要求IService1
的事物将获得单例,并且不调用任何构造函数。
这引起了人们的关注:
我以前见过这类问题,通常它们表示的是两件事之一:
这并不是说这些都是您要的,但这是我看到过此类问题的地方。通常,有一些潜意识中的目标是预先选择解决方案的,最好是问如何解决该目标,而不是如何实施一个非常具体的解决方案。再次,我可能是错的。
在上面第1项的重构说明中,基于对单例的需求,我可以进一步猜测是否存在某种资源,例如数据库连接需要共享或启动起来很昂贵。考虑将TComponent
分为三个单独的类:
TCommonExpensiveComponent
-这是旋转起来实际上很昂贵的东西,确实确实需要一个单例,但是在IService1
和IService2
之间并没有区别。TService1
-仅使用所需的构造函数实现IService1
,因此您不需要构造函数查找器。消耗TCommonExpensiveComponent
。TService2
-仅使用所需的构造函数实现IService2
,因此您不需要构造函数查找器。消耗TCommonExpensiveComponent
。该想法是避免注册的复杂性,保留所需的共享/单个,并且仍根据需要获得不同的构造函数用法。您可能还想抛出一些常见的基类/抽象类,如果确实存在很多常见逻辑,则TService
类可以派生自该类。
我要实现的概念上是错误的,Autofac是否不支持它,或者我只是缺少某些东西?
从技术上讲,如果您愿意,可以在Autofac中做一些非常疯狂的事情,例如编写自定义registration source,等待某人查询IService1
或IService2
注册,然后选择基于此的构造函数,根据需要动态提供注册服务。 但是,实际上,甚至不要走这条路。
相反,如果我的回答没有帮助,请弄清楚您要解决的问题以及解决上述挑战的计划是很好的。 在一个全新的问题中进行操作,该问题会更详细地介绍您的挑战和尝试过的事情。这不是一个论坛,而是通过对话进行尝试,以消除当前问题的实际帮助不可行另外,花点时间退后一步,也许重新构造问题听起来像在这里可能有所帮助。