MEF循环依赖

3
假设我们有两个组件相互依赖(间接地,通过接口):
public interface IAlice { ... }
public interface IBob { ... }

[Export(typeof(IAlice)), PartCreationPolicy(CreationPolicy.NonShared)]
class Alice : IAlice
{
    [Import]
    private IBob Bob { get; set; }
    ...
}

// could be defined in some assembly developed by another team
[Export(typeof(IBob)), PartCreationPolicy(CreationPolicy.NonShared)]
class Bob : IBob
{
    [Import]
    private IAlice Alice { get; set; }
    ...
}

这会导致组合失败:组合失败是因为它在“100”次迭代内没有完成。这很可能是由于一个部件的依赖关系图中存在循环,该部件标有非共享创建策略。
我知道我可以通过Lazy声明导入,但这样做时,导入将在需要时按需创建,而我需要我的Alice引用Bob,而Bob引用同一个Alice实例。我希望CompositionContainer能够在一个组合操作中解决这种循环依赖关系,但显然并非如此。
我不能将部件声明为共享,因为我不需要每个容器只有一个Alice和Bob。我只需要当在一个组合操作中完成时,这些依赖图作为一个整体被创建。是否有任何解决方法?
更新:添加了一些澄清。

您在我的回答评论中提到,Alice和Bob可能由不同的团队开发。如果是这种情况,那么Alice和Bob都不知道存在循环依赖关系,因此也不能期望它们都引用相同的实例。这表明您的懒惰方法是可接受的。我错过了什么吗? - Akash
是的,你说得对,懒惰的方法是可以接受的。我更喜欢允许懒惰和非懒惰的导入,但似乎MEF无法处理涉及非共享部分的非懒惰循环引用。因此,我们将限制所有属性导入为懒惰导入。感谢你的帮助! - yallie
1个回答

3
为什么不让Alice通过构造函数注入来导入IBob,然后显式设置Bob的Alice属性(即Bob不应该使用属性注入来设置Alice)?

我不应该将这些注入属性声明为公共的,很抱歉——已经修复了。关键是Alice和Bob是由不同的人开发的。Alice不知道Bob在使用它,而Bob也不知道它被Alice使用了。我们不允许构造函数注入,因为它可能导致这种循环依赖无法原则上解决,所以我们只能使用属性注入。 - yallie
必须有人理解循环依赖关系。将属性重新设为公共属性,但删除Import属性。现在定义Charlie(IAlice alice, IBob bob) { alice.Bob = bob; bob.Alice = alice; }。为Alice和Bob提供公共属性,并确保其他人只能通过这些属性访问Alice或Bob。 - Akash
感谢@Akash的建议,但我们无法以那种方式处理事情。在我们的情况下,Alice和Bob可以是由不同方开发的插件。我们并不知道其实现的任何细节。有人必须理解循环依赖关系。——我希望这个“有人”可以是MEF。只有MEF拥有组件之间所有内部依赖关系的完全知识。 - yallie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接