我使用windsor城堡作为我的IoC容器,并且遇到了一些问题。
但是由于循环引用被认为是“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/
答案 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);
...
}
}