【问题标题】:Windsor circular dependency of a transient-lifestyle component瞬态生活方式组件的温莎循环依赖
【发布时间】:2013-09-30 12:07:20
【问题描述】:

我有一堆这样写的类:

public class MyService1 {
    public MyService1(MyService1Settings settings, <service-dependent list of dependencies filled by Windsor>) { ... }
}

在温莎的注册是这样的:

container.Register(
    ...
    Component.For<MyService1>().LifestyleTransient(),
    Component.For<MyService2>().LifestyleTransient(),
    ...
);

容器没有注册任何 MyServiceXSettings 类型,因此获得服务的唯一方法是从容器中解析它,如下所示:

TService service = windsorContainer.Resolve<TService>(new { settings });

问题是,根据settings 对象中的参数,其中一个服务尝试使用不同设置对象获取其类型的另一个实例。

类似的东西:

public class MyService2 {
    public MyService2(MyService2Settings settings, <service-dependent list of dependencies filled by Windsor>)
    {
        this.uplink = settings.Counter == 1
            ? new AnotherUplink()
            : new RecursiveUplink(
                container.Resolve<MyService2>(new {
                    settings = new MyService2Settings(settings.Counter - 1)
                });
    }
}

这个递归依赖链是有限的(大约有 6 个实例深度),但是当第一个服务尝试获取另一个服务时,Windsor 会抛出异常,说明它是一个循环依赖。

我已将所有服务宣传为具有Transient 生活方式,并使用自定义参数请求它们。我至少可以指定递归的最大允许深度吗?还是我错过了另一种方法?

另一个要求:我不能使用类型化工厂,因为我有很多不同类型的服务,因此不希望为这些服务单独生成许多工厂接口。

【问题讨论】:

    标签: c# dependency-injection castle-windsor circular-dependency castle


    【解决方案1】:

    容器没有注册任何 MyServiceXSettings 类型, 所以获得服务的唯一方法是从容器中解决它 这个:

    您还可以在组件注册期间使用专用的 SubResolver 或 DependsOn。

    在构造函数中执行代码(而不是简单的变量赋值)是一种味道,使用容器更糟糕:它不应该在应用层泄漏。

    乍一看,您似乎只是在使用这些设置来选择构造函数中的正确组件:这应该在 CompositionRoot 完成,使用 TypedFactory 或 naming convention(您可能有多个注册相同的组件接口,但给定的参数名称驱动组件选择)

    【讨论】:

      【解决方案2】:

      根据this answer,我选择了懒惰的解决方案。

      /// <summary>
      /// Represents single component instance producer.
      /// </summary>
      /// <typeparam name="TComponent">type of the component to create</typeparam>
      public interface IComponentCreator<TComponent>
      {
          /// <summary>
          /// Gets the created component.
          /// </summary>
          TComponent Component { get; }
      }
      
      /// <summary>
      /// Creates the component only when it's first requested.
      /// </summary>
      /// <typeparam name="TComponent">type of the component to create</typeparam>
      public class LazyCreator<TComponent> : IComponentCreator<TComponent>
      {
          private readonly Func<TComponent> creatingFunction;
          private bool created;
          private TComponent component;
      
          public LazyCreator(Func<TComponent> creatingFunction)
          {
              this.creatingFunction = creatingFunction;
          }
      
          public TComponent Component
          {
              get
              {
                  if (!created)
                  {
                      component = creatingFunction();
                      created = true;
                  }
      
                  return component;
              }
          }
      }
      
      /// <summary>
      /// Returns already created component.
      /// </summary>
      /// <typeparam name="TComponent">type of the component</typeparam>
      public class ComponentContainer<TComponent> : IComponentCreator<TComponent>
      {
          private readonly TComponent component;
      
          public ComponentContainer(TComponent component)
          {
              this.component = component;
          }
      
          public TComponent Component
          {
              get { return component; }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-02
        相关资源
        最近更新 更多