仅在生命周期匹配时解析组件

Resolve component only if lifetime matches

接线示例:

// Module 1
builder.Register(ctx => new ServiceImpl1())
       .As<ISomeSubService>()
       .SingleInstance();

// Module 2
builder.Register(ctx => new MyComponent(ctx.Resolve<ISomeSubService>()))
       .As<IComponent>()
       .SingleInstance();

这是一个有效但危险的解决方案:如果稍后有人重构模块 1 并决定使用 ServiceImpl2(它可能不再是 SingleInstance-registrable),模块 2 会悄悄地引入一个错误。

如果 ctor 参数 ISomeSubService 的解析没有至少相同的生命周期,IComponent 的解析是否有可能失败?

Autofac 无法强制子依赖项的生命周期等于使用组件的生命周期。

如果你仔细想想,在很多情况下这实际上可能不是一个错误。

比如说,我有一个全局记录器。我可能会将其注册为 SingleInstance,因为它可以共享。

builder.RegisterType<MyLogger>()
       .As<ILogger>()
       .SingleInstance();

然后我可能会有一个需要记录器的 MVC 控制器。它只为一个请求而活。

builder.RegisterType<MyController>()
       .InstancePerRequest();

没关系。记录器应该跨事物共享,所以拥有不同的生命周期就好了。

现在切换它 - 假设您有一个存储库,可以调用从数据库获取本地化资源。它的创建成本很低,并且已注册 InstancePerDependency.

builder.RegisterType<MyResourceRepository>()
       .As<IResourceRepository>();
       .InstancePerDependency();

您在 Windows 表单应用程序中也有一个显示小部件,它显示一些本地化数据,但它在应用程序的整个生命周期内都存在 - 它是 SingleInstance

builder.RegisterType<MyWidget>()
       .SingleInstance();

它会在构建时获取资源存储库的副本,并且该资源存储库实例将在整个应用程序生命周期内保存它。 这不一定是错误。在许多情况下,这实际上可能很好。

与其尝试跨模块强制执行,不如让对象控制自己的生命周期,不要太担心。将事物注册到它们应该具有的生命周期范围内。

如果您担心单例组件可能会尝试获取它不应该为整个应用程序保持活动状态的服务,请在单例对象中 use the Func<T> relationship 自动解析一个factory 并调用函数来获取服务而不是挂在它上面。

public class A
{
  Func<B> _b;

  public A(Func<B> b) { _b = b; }

  public void M()
  {
    var b = _b();
    b.DoSomething();
  }
}

您也可以利用 the other implicit relationship types 来帮助处理此类问题。例如,如果您需要在使用完对象后对其进行处置,您可能需要一个 Func<Owned<T>> 以便您也可以控制处置。