使用IoC的循环参考 [英] Circular reference using IoC

查看:49
本文介绍了使用IoC的循环参考的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using windsor castle as my IoC container, and has run in to a bit of a problem.

首先-我知道: Castle Windsor:如何在工厂中防止循环引用创建的对象是创建的对象,是返回工厂的

但是由于循环引用被视为代码气味,因此我应该考虑重构应用程序架构

But since circular reference is considered as "Code Smell" and i should consider refactoring app architecture i am asking anyway.

我也有类似的情况:

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];
    }
}

现在我想从此代码中获取此OperationFactory温莎容器,这样我就可以轻松读取OperationCreatorBase的所有后续版本。

Now i would like to take in code this OperationFactory from windsor container so i can easily read all the successors of OperationCreatorBase.

现在有了OperationCreator的代码:

now there is a code for 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);
            .
            .
            .
      }
}

我真的想同时使用温莎城堡类,因为我使用了更多组件(例如Creator中的SomeHelper ...等)。在工厂类中,我使用了IKernel提供的不错的ResolveAll方法。

I really want to use windsor castle for both of this classes because i am using more components (such as SomeHelper in creator... and more). In factory class i am using nice method ResolveAll provided by IKernel.

有明显的构造函数循环引用,但我无法弄清楚,此组件设计有什么问题,最重要的是-

There is obvious constructor circular reference but i cant figure out, whats wrong with this component design and most important - how to make this runnable.

我知道我可以在两侧使用属性注入来做到这一点,但这杀死了这个不错的依赖注入功能,所以这就是为什么答案在上面说stackoverflow问题不会解决我的问题。我缺少什么吗?

I know i can do it with Property Injection on both sides but this kills this nice dependency injection feature, so thats why the answer said in upper stackoverflow question wont solve my problem. Am i missing something?

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

Is there any suggestion how to redesign those two components or how to Split the "C" class said in nice article about circular reference here: http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

推荐答案

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

In order to solve cyclic dependency you should inject Func<OperationsFactory> instead of OperationsFactory via constructor (or resolve using 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>

First OperationsFactory should be registered, then Func<OperationsFactory>.

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

我已经回答了类似的问题 Castle Windsor IoC对NHibernate ISession的循环依赖。您可以在此处找到更多详细信息。

I've already answered the similar question Cyclic dependency with Castle Windsor IoC for NHibernate ISession. You can find more details there.

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

If you already use IoC container it is better to inject instances of concrete types via constructor instead of IKernel. IKernel is a part of your infrastructure.

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

In order to resolve IEnumerable<T> CollectionResolver can be used.

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

If you cannot register Func<OperationsFactory> you can create it in the constructor in order to load OperationsFactory lazily.

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);
          ...
      }
}

这篇关于使用IoC的循环参考的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆