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

时间:2015-06-17 16:05:39

标签: c# .net autofac

连线示例:

// 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参数IComponent的解决方案至少没有相同的有效期,那么ISomeSubService的解决方案是否有可能失败?

1 个答案:

答案 0 :(得分:3)

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将自动解析工厂< / strong>并调用该函数来获取服务而不是挂在它上面。

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>>,以便您也可以控制处置。