2010-09-12 3 views
4

У меня есть круговая зависимость, недавно появившаяся из-за изменения архитектуры приложения.Ошибка MEF, была круговой зависимостью и теперь что-то еще

Приложение использует диспетчер плагинов, который загружает плагины через MEF. Все вплоть до работал нормально, потому что это выглядело примерно так:

// model.cs 
[Export("Model")] 
public class Model 
{ 
    public PluginManager PM { get; set; } 

    [ImportingConstructor] 
    public Model([Import] PluginManager plugin_manager) 
    { 
    PM = plugin_manager; 
    } 
} 

// pluginmanager.cs 
[Export(typeof(PluginManager))] 
public class PluginManager 
{ 
    [ImportMany(typeof(PluginInterface))] 
    private IEnumerable<PluginInterface> Plugins { get; set; } 
} 

и плагинов выглядит следующим образом:

// myplugin.cs 
[Export(typeof(PluginInterface))] 
public class MyPlugin : PluginInterface 
{ 
} 

Но теперь у меня есть ситуации, когда я хочу все плагины, чтобы иметь возможность запросить PluginManager (или, возможно, любой другой объект) через интерфейс, чтобы узнать о других плагинах в системе, чтобы узнать об их возможностях. Я «решил» это, добавив еще один интерфейс, назовем его PluginQueryInterface. Затем я использовал модель.

[Export("Model"))] 
[Export(typeof(PluginQueryInterface))] 
public class Model : PluginQueryInterface 
{ 
    // same as before 
} 

, а затем плагин подписи будет выглядеть следующим образом:

// 1st possible implementation 
[Export(typeof(PluginInterface))] 
public class MyPlugin : PluginInterface 
{ 
    [Import(typeof(PluginQueryInterface))] 
    public PluginQueryInterface QueryInterface { get; set; } 

    public MyPlugin() {} 
} 

или этого

// 2nd possible implementation 
[Export(typeof(PluginInterface))] 
public class MyPlugin : PluginInterface 
{ 
    private PluginQueryInterface QueryInterface { get; set; } 

    [ImportingConstructor] 
    public MyPlugin([Import] PluginQueryInterface query_interface) 
    { 
    QueryInterface = query_interface 
    } 
} 

второй реализация довольно четко циклическая ссылка, потому что плагины требует создания PluginQueryInterface до создания плагина, но t он PluginQueryInterface - это модель, которая должна импортировать PluginManager, который, в свою очередь, нуждается во всех созданных PluginInterfaces ... и при запуске я получаю ошибку зависимости MEF.

Реализация не кажется круговой ссылкой на меня. Если PluginQueryInterface является свойством, то я думал, что он не будет разрешен , пока не будет использован. И он вообще не используется конструктором. Так почему бы не PluginManager весело создавать все мои MyPlugins? Я получаю ту же ошибку MEF в обоих случаях.

Я попытался решить эту проблему, создав PluginManager для реализации PluginQueryInterface, потому что a) имеет смысл в любом случае и b) это known way of dealing with circular dependencies - заставьте два взаимозависимых класса вместо этого зависеть от третьего класса. Теперь проблема в том, что я получаю другую ошибку MEF! Это то, что он говорит:

GetExportedValue cannot be called before prerequisite import 'Company.App.PluginManager..ctor(Parameter="database_filepath", ContractName="PluginManager.filename")' has been set. 

WTF? Я установил контрольные точки в своем коде, и мое экспортированное значение PluginManager.filenameустановило перед вызовом GetExportedValue.

Я полностью в тупике. Любые замечания или предложения будут в значительной степени оценены прямо сейчас. Я несколько часов стучал головой о стену, покрытую MEF, пытаясь отладить эту проблему.

(обновлено)

Я не думал об этом раньше, но это могло бы быть различия между плагинами, поэтому я удалил один из двух модулей, и теперь мои нагрузки приложений без MEF ошибок. Я добавил его обратно, и он снова не удался. Затем я удалил другой плагин, и он сработал. Таким образом, похоже, что это еще одна ошибка MEF.Это почти так, как будто я не хочу, чтобы я загружал больше одного плагина с определенным интерфейсом ... но я использую ImportMany, и не будет ли это проявляться как CardinalityException?

UPDATE

Я не понимаю эту часть MEF, и, надеюсь, кто-то здесь может объяснить, что это все о. После некоторого времени вступая в код, я обнаружил, что моя ошибка возникла из-за того, что MEF удалил определения импорта после нахождения значения!

private bool TryGetImportValue(ImportDefinition definition, out object value) 
    { 
     lock (this._lock) 
     { 
      if (this._importValues.TryGetValue(definition, out value)) 
      { 
       this._importValues.Remove(definition); // this is the line that got me 
       return true; 
      } 
     } 

     value = null; 
     return false; 
    } 

Я никогда не имел эту проблему раньше, и, честно говоря, я с трудом понимая, что я делаю сейчас с моим импортом и экспортом, что сделал эту поверхность проблемы. Я предполагаю, что я делаю то, что дизайнеры MEF не собирались делать. I мог слепо прокомментировать this._importValues.Remove(definition);, но это, возможно, не так. Я предполагаю, что это сводится к атрибутам MEF, которые я использовал, но так как плагин, который импортирует это значение, имеет политику создания CreationPolicy.Shared, почему у меня есть проблема?

ответ

3

Ну, у меня есть возможное решение. У меня нет опыта использования этого, но использование Lazy, похоже, помогает. По крайней мере, я могу двигаться вперед, не меняя код MEF, который я не совсем понимаю.

 Смежные вопросы

  • Нет связанных вопросов^_^