如何在Autofac同一作用域中注入已构造解析的实例?
嘿,刚接触Autofac碰到这种依赖共享的问题太正常了,我来给你捋捋可行的方案,顺便解答你的疑问:
1. 让ServiceB和MyConsumer拿到同一个IServiceA实例
Autofac默认的服务生命周期是InstancePerDependency——意思是每次解析都会生成新实例,这就是你目前得到不同IServiceA的原因。要实现共享,你可以根据实际场景选下面两种注册方式:
选项一:同一生命周期域内共享(最常用)
如果希望在同一个业务操作/请求范围内,所有用到的IServiceA都是同一个实例,用InstancePerLifetimeScope来注册:
var builder = new ContainerBuilder(); // 注册IServiceA为「每个生命周期域内单例」 builder.RegisterType<ServiceA>().As<IServiceA>().InstancePerLifetimeScope(); builder.RegisterType<ServiceB>().As<IServiceB>(); builder.RegisterType<MyConsumer>(); var container = builder.Build(); // 在一个生命周期域内解析MyConsumer using (var scope = container.BeginLifetimeScope()) { var consumer = scope.Resolve<MyConsumer>(); // 这里consumer._serviceA 和 consumer._serviceB里的_serviceA是完全相同的实例 }
当你在一个LifetimeScope里解析MyConsumer时,Autofac会在这个域内复用IServiceA的实例——不管是直接注入给MyConsumer,还是通过ServiceB的构造函数注入,都会拿到同一个对象。
选项二:仅为MyConsumer及其依赖链共享(贴合你的「类构造定义作用域」需求)
如果你想让每个MyConsumer实例拥有专属的IServiceA,且这个实例会被MyConsumer的所有依赖(比如ServiceB)共享,那用InstancePerOwned<MyConsumer>()注册就刚好:
var builder = new ContainerBuilder(); // 注册IServiceA为「每个MyConsumer实例所属的作用域内单例」 builder.RegisterType<ServiceA>().As<IServiceA>().InstancePerOwned<MyConsumer>(); builder.RegisterType<ServiceB>().As<IServiceB>(); builder.RegisterType<MyConsumer>();
效果就是:
var consumer1 = container.Resolve<MyConsumer>(); var consumer2 = container.Resolve<MyConsumer>(); // consumer1的两个IServiceA是同一个,consumer2的两个也是同一个,但consumer1和consumer2的IServiceA完全独立
这种方式完美对应你说的「作用域由类的构造函数自然定义」——MyConsumer的实例就是作用域的边界,它的所有依赖共享同一个IServiceA,不同的MyConsumer实例互不干扰。
2. 构造函数参数顺序的问题
完全不用担心!Autofac是根据参数的类型来匹配依赖,和参数顺序一点关系都没有。不管你把IServiceA和IServiceB的顺序怎么调换,Autofac都能准确找到对应的注册服务,不会出现解析错误或者意外结果。你完全可以让MyConsumer只关注需要的依赖类型,不用操心参数排列顺序。
关于你提到的Scope Convention疑问
其实Autofac的InstancePerLifetimeScope和InstancePerOwned<T>就是为这种「作用域内共享实例」设计的机制。你觉得「作用域由类的构造函数自然定义」,InstancePerOwned<T>正好契合这个场景——它把T的实例作为作用域的起点,T的所有依赖链中的服务都会在这个专属的嵌套作用域里共享实例。
另外,如果是在ASP.NET这类框架里使用Autofac,它会自动和请求生命周期绑定,InstancePerLifetimeScope(ASP.NET Core)或者InstancePerRequest(传统ASP.NET)会自动帮你在请求范围内共享实例,完全不用手动管理作用域,非常省心。
内容的提问来源于stack exchange,提问作者Hopeless

