Циклическая зависимость MEF

Предположим, у нас есть два компонента, зависящих друг от друга (косвенно, через интерфейсы):

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» итераций. Это, скорее всего, вызвано циклом в графе зависимостей части, которая помечена политикой создания без общего доступа.

Я знаю, что могу импортировать через ленивое объявление, но таким образом импорт будет создаваться по запросу, в то время как мне нужно, чтобы моя Алиса ссылалась на Боба, а Боб ссылался на один и тот же экземпляр Алисы. Я ожидал, что CompositionContainer разрешит такие циклы в рамках одной операции композиции, но, видимо, это не так.

Я не могу объявить части как общие, так как мне не нужны отдельные Алиса и Боб для каждого контейнера. Мне просто нужно, чтобы такие графы зависимостей создавались как единое целое, когда это делается за одну операцию композиции. Есть ли обходной путь?

УПД. Добавил некоторые уточнения.


person yallie    schedule 17.03.2012    source источник
comment
Вы упомянули в комментарии к моему ответу, что Алиса и Боб могут быть разработаны разными сторонами. Если это так, то ни Алиса, ни Боб не знают о наличии циклической зависимости, следовательно, ни один из них не может ожидать, что они оба ссылаются на один и тот же экземпляр. Это говорит о том, что ваш ленивый подход приемлем. Что мне не хватает?   -  person Akash    schedule 22.03.2012
comment
Да, вы правы, ленивый подход приемлем. Я бы предпочел разрешить как ленивый, так и неленивый импорт, но похоже, что MEF не может обрабатывать неленивые циклические ссылки, включающие неразделяемые части. Поэтому мы ограничим импорт всех свойств ленивыми. Спасибо за вашу помощь!   -  person yallie    schedule 23.03.2012


Ответы (1)


Почему бы Алисе не импортировать IBob через внедрение ctor, а затем явно установить свойство Alice для Боба (т. е. Боб не должен использовать внедрение свойства для Алисы)?

person Akash    schedule 17.03.2012
comment
(Я не должен был объявлять эти свойства инъекции как общедоступные, извините — исправлено). Дело в том, что Алису и Боба разрабатывают разные люди. Алиса не знает, что его использует Боб, а Боб не знает, что его использует Алиса. Мы не разрешаем внедрение ctor, потому что это может привести к ситуации, когда эта циклическая зависимость не может быть разрешена в принципе, поэтому мы застряли на внедрении свойств. - person yallie; 18.03.2012
comment
Кто-то должен понимать круговую зависимость. Снова сделайте свойства общедоступными, но удалите атрибут Import. Теперь определите Charlie(IAlice alice, IBob bob) { alice.Bob = bob; bob.Alice = alice; }. Предоставьте Чарли общедоступные свойства для Алисы и Боба и убедитесь, что другие получают доступ к Алисе или Бобу только через эти свойства. - person Akash; 18.03.2012
comment
Спасибо @Akash за ваши предложения, но мы просто не можем так поступать. В нашем случае Алиса и Боб могут быть плагинами, разработанными разными сторонами. И нам неизвестны подробности их реализации. Кто-то должен понимать циклическую зависимость. — я надеялся, что этим Кто-то может быть MEF. Только MEF обладает полной информацией обо всех внутренних зависимостях между компонентами. - person yallie; 19.03.2012