代码之家  ›  专栏  ›  技术社区  ›  Dave

MEF错误,是循环依赖项,现在是其他内容

  •  4
  • Dave  · 技术社区  · 14 年前

    我最近有一个循环依赖,这是因为我的应用程序架构发生了变化。

    应用程序依赖于插件管理器,该管理器通过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,但是PluginQueryInterface是模型,它必须导入PluginManager,而PluginManager又需要创建所有的plugininterface。。。当我启动时,我得到了一个MEF循环依赖错误。

    这个 对我来说,实现似乎不是循环引用。如果PluginQueryInterface是一个属性,那么我认为它不会被解析 直到它被使用 . 构造函数根本不使用它。那么为什么PluginManager不能愉快地创建我所有的MyPlugins呢?在这两种情况下,我得到相同的MEF错误。

    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.
    

    世界跆拳道联盟?我在代码中设置断点,并导出值 PluginManager.filename 已在调用GetExportedValue之前设置。

    (已更新)

    我之前没有考虑过这个问题,但可能是插件之间的差异,所以我删除了两个插件中的一个,现在我的应用程序加载时没有MEF错误。我又加了回去,结果又失败了。然后我删除了另一个插件,它成功了。看来这是另一个MEF错误。这几乎就像它不想让我加载多个插件与一个特定的接口。。。但我用的是ImportMany,那不就是 CardinalityException

    我不理解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;
        }
    

    能够 盲目地评论 this._importValues.Remove(definition); ,但那不可能是对的。我猜这将归结为我使用的MEF属性,但是由于导入这个值的插件有一个创建策略 CreationPolicy.Shared

    2 回复  |  直到 14 年前
        1
  •  3
  •   Dave    14 年前

    嗯,我有个可能的解决办法。我没有使用这个的经验,但是 Lazy