0

我使用溫莎城堡作爲我IoC容器,並在一個有點問題的運行。循環引用國際奧委會使用

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

但由於循環引用被認爲是「代碼味道」,我應該考慮重構應用程序架構我問反正。

我有非常類似的情況:

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所有的接班人。

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

我真的想因爲我用更多的組件使用溫莎城堡兩個本類(在創作者如SomeHelper ...等等)。在工廠類中,我使用IKernel提供的很好的方法ResolveAll。

有明顯的構造循環引用,但我不能弄清楚,什麼是錯與此組件的設計和最重要的 - 如何使這個運行的。

我知道我可以在兩側地產注入做,但這個殺死這個漂亮的依賴注入的功能,所以這就是爲什麼答案在計算器上提問時說不會解決我的問題。我錯過了什麼嗎?

是否有任何建議,如何重新設計這兩種組件或如何分割「C」類中有關循環引用在這裏很好的文章說:http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

回答

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

感謝您的回覆。我知道關於構造函數中的具體類型,而且我正在使用具體類型,只要我可以,購買你是正確的,在例子中我使用IKernel這是我的錯。第二你知道什麼是windsor城堡XML配置替代... UsingFactoryMethod(...)? – LightCZ

+0

我不這麼認爲。 [官方網站](http://docs.castleproject.org/Windsor.MainPage.ashx)引用了一段話:「在[Fluent註冊API]之前,能夠註冊XML的組件大部分是溫莎早期的剩餘部分, (http://docs.castleproject.org/Windsor.Fluent-Registration-API.ashx),它比代碼中的註冊功能強大得多,許多任務只能通過代碼完成。「 –

+0

@LightCZ,如果您無法註冊Func ,您可以在構造函數中創建它以便加載OperationsFactory。 –

相關問題