嗯,我认为这是可能的,但不确定如何做到这一点。这是我的场景:我有2个服务,一个依赖于另一个,像这样:
public interface IServiceA {
//...
}
public interface IServiceB {
//...
}
//the actual implementation
public class ServiceA : IServiceA {
//...
}
public class ServiceB : IServiceB {
readonly IServiceA _serviceA;
public ServiceB(IServiceA serviceA){
_serviceA = serviceA;
}
}
我有另一个类消耗这两种服务:
public class MyConsumer {
readonly IServiceA _serviceA;
readonly IServiceB _serviceB;
public MyConsumer(IServiceA serviceA, IServiceB serviceB){
_serviceA = serviceA;
_serviceB = serviceB;
}
}
所以我希望在serviceB
的构造函数中向serviceA
注入MyConsumer
的解析内容。 (意味着注入serviceA
的{{1}}应该是注入ServiceB
的实例serviceA
- 而不是一些新的不同实例)。
请注意:我不希望通过MyConsumer
公开ServiceA
,只让ServiceB
仅依赖于MyConsumer
(实际上IServiceB
是基本服务,而其他包括ServiceA
在内的服务只是扩展,这意味着在这种情况下可能会有更多服务,例如ServiceB
我是Autofac的新手,甚至是Unity(我用过的最多)我以前从未想过这个场景,所以到目前为止我还没有任何代码。
我希望此处有人遇到过同样的情况,可以提供一些建议,谢谢!
加分问题:如果参数(传入的ServiceB
构造函数)的顺序发生了变化怎么办?我的意思是这会影响解决顺序并导致意外结果吗?如果可能,参数顺序无关紧要(因为MyConsumer
应该只关心它需要什么,而不是如何订购所需的东西。
问题的大图:
有些人建议在某些情况下使用autofac支持的MyConsumer
。不过我的情况有所不同,我认为强制autofac理解我想要的东西并不是很方便。
这里defined scope
实际上永远不会直接解析(使用MyConsumer
方法)因为它可能只是另一个类的依赖(我们称之为.Resolve
)。
通过使用.Resolve
,我认为这是正确的方法,但我的情况下的范围是不同的,我认为它是由类的构造函数自然定义的(注入的所有依赖项应该在同一范围内 - 以及每个类型的实例)在该范围内应该是一个单独的 - 在它们之间共享。不知道为什么Autofac可以为我们提供这一点。
答案 0 :(得分:1)
这是另一个答案的独立解决方案,希望能解决您对容器特殊用途的担忧:
namespace AutofacTest
{
public interface IServiceA { }
public interface IServiceB { }
public class ServiceA : IServiceA
{
}
public class ServiceB : IServiceB
{
private readonly IServiceA _serviceA;
public ServiceB (IServiceA serviceA)
{
_serviceA = serviceA;
}
}
public class MyConsumer
{
private readonly IServiceA _serviceA;
private readonly IServiceB _serviceB;
public MyConsumer(Func<IServiceA> serviceAFactory, Func<IServiceA, IServiceB> serviceBFactory)
{
_serviceA = serviceAFactory();
_serviceB = serviceBFactory(_serviceA);
}
}
}
在这个解决方案中,我注入工厂而不是实例,然后调用它们来获取实例。关于这个实现有点丑陋的一点是参数顺序现在很重要。
如果您真的不想让订单变得重要,您可以在IServiceA
界面上为IServiceB
公开一个setter,然后用
public MyConsumer(Func<IServiceA> serviceAFactory, Func<IServiceB> serviceBFactory)
{
_serviceA = serviceAFactory();
_serviceB = serviceBFactory(_serviceA);
_serviceB.SetServiceA(_serviceA);
}
答案 1 :(得分:0)
我把一些我觉得适合你情况的小样本放在一起:
namespace AutofacTest
{
public interface IServiceA { }
public interface IServiceB { }
public interface IMyConsumer { }
public class ServiceA : IServiceA
{
}
public class ServiceB : IServiceB
{
private readonly IServiceA _serviceA;
public ServiceB (IServiceA serviceA)
{
_serviceA = serviceA;
}
}
public class MyConsumer : IMyConsumer
{
private readonly IServiceA _serviceA;
private readonly IServiceB _serviceB;
public MyConsumer(IServiceA serviceA, IServiceB serviceB)
{
_serviceA = serviceA;
_serviceB = serviceB;
}
}
public class AutofacInit
{
public IContainer BuildContainer()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ServiceA>().AsImplementedInterfaces().InstancePerLifetimeScope();
containerBuilder.RegisterType<ServiceB>().AsImplementedInterfaces().InstancePerLifetimeScope();
containerBuilder.RegisterType<MyConsumer>().AsImplementedInterfaces().InstancePerLifetimeScope();
return containerBuilder.Build();
}
public void Test()
{
using (var container = BuildContainer())
{
using (var myConsumer = container.Resolve<Owned<IMyConsumer>>())
{
//use myConsumer.Value
}
}
}
}
}
我正在使用嵌套的生命周期范围(通过解析Owned<IMyConsumer>
创建),其中只存在IServiceA
,IServiceB
和IMyConsumer
的一个实例。需要注意的一点是,如果采用这种方法,您应始终解析/注入Owned<IMyConsumer>
并永远不要解析/注入普通IMyConsumer
,否则IServiceA
和{{1}依赖关系将是单身人士。
这也应该处理你的红利问题 - 这个样本中的任何内容都不关心参数的排序。
答案 2 :(得分:0)
对我而言,您需要做的就是确保所有这些内容 - MyConsumer
,ServiceA
和ServiceB
(以及其他“扩展名”) - 注册为InstancePerLifetimeScope()
。只要它们从相同的范围内解决,它们都将成为该范围的“单身人士”。你在代码中试过了吗?如果你在使用这种方法时遇到问题,那么你需要在你的问题中明确说出来,因为很难弄清楚你的真正问题是什么。我个人认为问题不在于autofac本身或是否适合你的服务,它只是缺乏对新DI容器的熟悉 - 这是很自然的事情,每种新技术都有它的学习曲线。只要继续尝试,继续尝试,你就会完成它。 Autofac是非常强大的DI容器,所以我很确定它可以做你想要的。