使用IoC的循环引用

时间:2014-03-18 19:12:04

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

我使用windsor城堡作为我的IoC容器,并且遇到了一些问题。

首先 - 我知道:Castle Windsor: How to prevent circular references in factory-created objects were the created objects refers back to the factory

但是由于循环引用被认为是“Code Smell”,我应该考虑重构应用程序架构,无论如何我都会问。

我的情况非常相似:

public class OperationsFactory
{
    private GeneralSettingsManager m_generalSettings;
    private Dictionary<OperationType, OperationCreatorBase> m_creators;

    public OperationsFactory(IKernel container)
    {
        m_generalSettings = container.Resolve<GeneralSettingsManager>();
        var creators = container.ResolveAll<OperationCreatorBase>(); //FIRST DEPENDENCY

        foreach (var creator in creators)
        {
            m_creators.Add(creator.CreatorOperationType, creator);
        }
    }
.
.
.
    private OperationCreatorBase GetCreator(OperationType operationType)
    {
        return m_creators[operationType];
    }
}

现在我想从windsor容器中获取这个OperationFactory的代码,这样我就可以轻松阅读OperationCreatorBase的所有后继版本。

现在有一个OperationCreator的代码:

public class ConvertToFullOperationCreator : OperationCreatorBase
{

    private OperationsFactory m_operationsFactory;
    private SomeHelper m_someHelper;

    public ConvertToFullOperationCreator(IKernel container)
    {
       m_operationsFactory = container.Resolve<OperationsFactory>(); //SECOND dependency which causes error
       m_someHelper = container.Resolve<SomeHelper>();
    }

    public override OperationType CreatorOperationType
    {
        get { return OperationType.SomeOperation2; }
    }

    public override List<OperationBase> CreateOperation(FileData fileData)
    {
          //HERE I WANT TO USE FACTORY to get creators for SUBOPERATIONS
           var creator1 = m_operationsFactory.GetCreator(OperationType.SomeSuboperation1);
           creator1.CreateOperation(fileData);
            .
            .
            .

            m_someHelper.DoSomething(fileData);

           var creator2 = m_operationsFactory.GetCreator(OperationType.SomeSuboperation2);
           creator2.CreateOperation(fileData);
            .
            .
            .
      }
}

我真的想在这两个类中使用windsor城堡,因为我使用了更多组件(例如创建者中的SomeHelper ......等等)。在工厂类中,我使用的是由IKernel提供的好方法ResolveAll。

有明显的构造函数循环引用,但我无法弄清楚,这个组件设计有什么问题,最重要的是 - 如何使这个可运行。

我知道我可以在两侧使用Property Injection来实现它,但这会杀死这个很好的依赖注入功能,所以这就是为什么答案在上层stackoverflow问题中说不会解决我的问题。我错过了什么吗?

是否有任何建议如何重新设计这两个组件或如何拆分“C”类在这里关于循环引用的好文章中说:http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

1 个答案:

答案 0 :(得分:0)

为了解决循环依赖关系,您应该通过构造函数注入Func<OperationsFactory>而不是OperationsFactory(或使用IKernel / IWindsorContainer解析)。

public class ConvertToFullOperationCreator : OperationCreatorBase
{        
    private Func<OperationsFactory> get_operationsFactory;
    private SomeHelper m_someHelper;

    public ConvertToFullOperationCreator(
            SomeHelper someHelper,
            Func<OperationsFactory> get_operationsFactory)
    {
       this.get_operationsFactory = get_operationsFactory
       m_someHelper = someHelper;
    }

    public override List<OperationBase> CreateOperation(FileData fileData)
    {
          var m_operationsFactory = get_operationsFactory()
          // Here you can place all your code
          var creator1 = m_operationsFactory
                .GetCreator(OperationType.SomeSuboperation1);
          ...
          var creator2 = m_operationsFactory
                .GetCreator(OperationType.SomeSuboperation2);
          ...
      }
}

首先应注册OperationsFactory,然后Func<OperationsFactory>

container.Register(Component.For<Func<OperationsFactory>>()
    .UsingFactoryMethod(container =>
    {
        Func<OperationsFactory> func = container.Resolve<OperationsFactory>;
        return func;
    }));

我已经回答了类似问题Cyclic dependency with Castle Windsor IoC for NHibernate ISession。你可以在那里找到更多细节。

如果您已经使用了IoC容器,最好通过构造函数而不是IKernel注入具体类型的实例。 IKernel是您基础架构的一部分。

要解决IEnumerable<T> CollectionResolver可以使用。

public class OperationsFactory
{
    private GeneralSettingsManager m_generalSettings;
    private Dictionary<OperationType, OperationCreatorBase> m_creators;

    public OperationsFactory(
            GeneralSettingsManager generalSettings,
            IEnumerable<OperationCreatorBase> creators)
    {
        m_generalSettings = generalSettings;
        foreach (var creator in creators)
        {
            m_creators.Add(creator.CreatorOperationType, creator);
        }
    }
    ...
}

编辑:

如果您无法注册Func<OperationsFactory>,可以在构造函数中创建它,以便懒惰地加载OperationsFactory

public class ConvertToFullOperationCreator : OperationCreatorBase
{        
    private Func<OperationsFactory> get_operationsFactory;
    private SomeHelper m_someHelper;

    public ConvertToFullOperationCreator(
            IKernel container)
    {
       this.get_operationsFactory = () => container.Resolve<OperationsFactory>;
       m_someHelper = container.Resolve<SomeHelper>();
    }

    public override List<OperationBase> CreateOperation(FileData fileData)
    {
          var m_operationsFactory = get_operationsFactory()
          // Here you can place all your code
          var creator1 = m_operationsFactory
                .GetCreator(OperationType.SomeSuboperation1);
          ...
          var creator2 = m_operationsFactory
                .GetCreator(OperationType.SomeSuboperation2);
          ...
      }
}