Autofac如何根据上下文使用默认和非默认的ctor



我有两个类,比如:

public class P 
{
public P( Guid g )  {}
}
public class Lp
{
public Lp() {}
public Lp( P p ) {}
}   

我用Autofac 6.2.0注册了这两个,比如:

builder.RegisterType< P >();
builder.RegisterType< Lp >();

现在我想使用默认的ctor来解析Lp。当我试图解决Lp类似:

var c = builder.Build();
using( var scope = c.BeginLifetimeScope() )
{
scope.Resolve<Lp>();
}

我得到一个错误,即为类型P找到的构造函数都不能用可用的服务和参数调用。是的,这是真的。

显然,由于类型P已经注册,Autofac认为它应该能够创建P并使用它来创建Lp,而不是认识到它无法在没有Guid的情况下创建P,从而使用默认的Lpctor。如果我没有注册P,则解析成功。如果我向P添加一个默认的ctor,则解析成功(除了它使用非默认的Lpctor(。

诊断不是很有趣,但看起来像:

{   Resolve Request Starting   {
Service: CtsMasterTs.Positions.Lp
Component: CtsMasterTs.Positions.Lp
Pipeline:
-> CircularDependencyDetectorMiddleware
-> ScopeSelectionMiddleware
-> SharingMiddleware
-> RegistrationPipelineInvokeMiddleware
-> ActivatorErrorHandlingMiddleware
-> DisposalTrackingMiddleware
-> Lp (ReflectionActivator)
Resolve Request Starting
{
Service: CtsMasterTs.Positions.P
Component: CtsMasterTs.Positions.P
Pipeline:
-> CircularDependencyDetectorMiddleware
-> ScopeSelectionMiddleware
-> SharingMiddleware
-> RegistrationPipelineInvokeMiddleware
-> ActivatorErrorHandlingMiddleware
-> DisposalTrackingMiddleware
-> P (ReflectionActivator)
X- P (ReflectionActivator)
X- DisposalTrackingMiddleware
X- ActivatorErrorHandlingMiddleware
X- RegistrationPipelineInvokeMiddleware
X- SharingMiddleware
X- ScopeSelectionMiddleware
X- CircularDependencyDetectorMiddleware
}
Resolve Request FAILED
Autofac.Core.DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'CtsMasterTs.Positions.P' can be invoked with the available services
and parameters:
Cannot resolve parameter 'System.Guid g' of constructor 'Void .ctor(System.Guid)'.
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetAllBindings(ConstructorBinder[]
availableConstructors, IComponentContext context, IEnumerable`1
parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
175
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext
context, IEnumerable`1 parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
134
at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext
ctxt, Action`1 next) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
104
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs:line
32
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs:line
36
X- Lp (ReflectionActivator)
X- DisposalTrackingMiddleware
X- ActivatorErrorHandlingMiddleware
X- RegistrationPipelineInvokeMiddleware
X- SharingMiddleware
X- ScopeSelectionMiddleware
X- CircularDependencyDetectorMiddleware   }   Resolve Request FAILED: Nested Resolve Failed } Operation FAILED  
Autofac.Core.DependencyResolutionException: An exception was thrown
while activating CtsMasterTs.Positions.Lp -> CtsMasterTs.Positions.P.
---> Autofac.Core.DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'CtsMasterTs.Positions.P' can be invoked with the available services
and parameters:   Cannot resolve parameter 'System.Guid g' of
constructor 'Void .ctor(System.Guid)'.
at Autofac.Core.Activators.Reflection.ReflectionActivator.GetAllBindings(ConstructorBinder[]
availableConstructors, IComponentContext context, IEnumerable`1
parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
175
at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext
context, IEnumerable`1 parameters) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
134
at Autofac.Core.Activators.Reflection.ReflectionActivator.<ConfigurePipeline>b__11_0(ResolveRequestContext
ctxt, Action`1 next) in
/_/src/Autofac/Core/Activators/Reflection/ReflectionActivator.cs:line
104
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.DisposalTrackingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/DisposalTrackingMiddleware.cs:line
32
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs:line
36
--- End of inner exception stack trace ---
at Autofac.Core.Resolving.Middleware.ActivatorErrorHandlingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/ActivatorErrorHandlingMiddleware.cs:line
48
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.SharingMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/SharingMiddleware.cs:line 58
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.Middleware.CircularDependencyDetectorMiddleware.Execute(ResolveRequestContext
context, Action`1 next) in
/_/src/Autofac/Core/Resolving/Middleware/CircularDependencyDetectorMiddleware.cs:line
94
at Autofac.Core.Resolving.Pipeline.ResolvePipelineBuilder.<>c__DisplayClass14_0.<BuildPipeline>b__1(ResolveRequestContext
ctxt) in
/_/src/Autofac/Core/Resolving/Pipeline/ResolvePipelineBuilder.cs:line
262
at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope
currentOperationScope, ResolveRequest request) in
/_/src/Autofac/Core/Resolving/ResolveOperation.cs:line 150
at Autofac.Core.Resolving.ResolveOperation.ExecuteOperation(ResolveRequest
request) in /_/src/Autofac/Core/Resolving/ResolveOperation.cs:line 182

这对我来说是个问题,因为我需要能够创建带有或不带有PLp。在代码的其他地方,我使用注入的Func<Lp>Func<P, Lp>作为工厂。我还使用注入的Func<Guid, P>来创建P对象。

所以我的问题是-我该怎么做:

A( 让Autofac查看Pctor,并了解它不能在没有P参数或的情况下使用非默认Lpctor

B( 以其他方式使用一些Autofac魔术(例如lambda注册?(以允许Func<Lp>Func<P, Lp>都工作?我简要介绍了使用ctor选择,但似乎每次解析类型时都会强制使用相同的ctor。

其他信息-。Net Framework 4.8,VS2019,Windows 10,WPF。这是一个简单的例子,展示了我(更复杂(的应用程序代码中发生的事情。

更新-这是代码气味吗?我仍在努力解决这个问题。

用例是p是不可变的。Lp是";可编辑";当需要新的P时,我用默认的ctor创建一个新的Lp,编辑属性值,然后用Lp从中创建一个P。CreateP((。如果P已经存在并且需要编辑,我使用Lp(P I_P(创建一个新的Lp,编辑特性值,然后使用Lp用新的P替换原始P。CreateP((。这对我来说似乎很合理,但也许我错过了什么。

这并不是一个常见的用例。绝大多数用途是:

  • 选择应该始终使用的构造函数(可以使用带有P的构造函数,也可以不使用,但不能"上下文不同"(;或
  • 使用可以由DI中最可用的东西填充的构造函数(这是Autofac的默认行为(

这个用例更像是"我想在这个嵌套的范围中使用默认的Autofac behavior _except,我需要覆盖使用的构造函数"我建议分析需要这样做的设计,因为它看起来像是一种代码气味。

但是,您能做的最好的事情是在子生存期范围中重新注册Lp,并强制使用您想要的构造函数。解决方案将基于覆盖进行,并且应该按照您的意愿进行。

var builder = new ContainerBuilder();
builder.RegisterType<P>();
builder.RegisterType<Lp>();
var container = builder.Build();
// This will use the `Lp(P)` constructor - most matched
var first = container.Resolve<Lp>();
using(var scope = container.BeginLifetimeScope(b =>
{
b.RegisterType<Lp>().UsingConstructor(Array.Empty<Type>());
})
{
// This should use the default no-parameter constructor.
var second = scope.Resolve<Lp>();
}

相关内容

最新更新