2010-04-19 174 views
0

这是我之前发表的一篇文章的延续,其中涉及到解决WPF应用程序中的模块问题。这个问题与模块相互依存关系的影响以及构建这些模块的方法(即通过MEF或通过new)具体涉及MEF解决关系的能力。无法解决MEF导入问题

我已经尝试了两种方法:

  • 左侧的方法:应用实施IERROR
  • 正确做法:在App具有实现IERROR

左胸成员

我的代码看起来像这样(只是MEF相关的东西):

// app.cs 
[Export(typeof(IError))] 
public partial class Window1 : Window, IError 
{ 
    [Import] 
    public CandyCo.Shared.LibraryInterfaces.IPlugin Plugin { get; set; } 
    [Import] 
    public CandyCo.Shared.LibraryInterfaces.ICandySettings Settings { get; set; } 

    private ICandySettings Settings; 

    public Window1() 
    { 
     // I create the preferences here with new, instead of using MEF. I wonder 
     // if that's my whole problem? If I use MEF, and want to have parameters 
     // going to the constructor, then do I have to [Export] a POCO (i.e. string)? 
     Settings = new CandySettings("Settings", @"c:\settings.xml"); 

     var catalog = new DirectoryCatalog("."); 
     var container = new CompositionContainer(catalog); 
     try { 
      container.ComposeParts(this); 
     } catch(CompositionException ex) { 
      foreach(CompositionError e in ex.Errors) { 
       string description = e.Description; 
       string details = e.Exception.Message; 
      } 
      throw; 
     } 
    } 
} 

// plugin.cs 
[Export(typeof(IPlugin))] 
public class Plugin : IPlugin 
{ 
    [Import] 
    public CandyCo.Shared.LibraryInterfaces.ICandySettings CandySettings { get; set; } 
    [Import] 
    public CandyCo.Shared.LibraryInterfaces.IError ErrorInterface { get; set; } 

    [ImportingConstructor] 
    public Plugin(ICandySettings candy_settings, IError error_interface) 
    { 
     CandySettings = candy_settings; 
     ErrorInterface = error_interface; 
    } 
} 

// candysettings.cs 
[Export(typeof(ICandySettings))] 
public class CandySettings : ICandySettings 
{ 
    ... 
} 

右侧接近

基本上一样的左侧的方式,所不同的是我创建的从IERROR继承在同一组件Window1中的类。然后我使用[Import]来尝试​​让MEF为我解决这个问题。

任何人都可以解释我在这里接触MEF的两种方式是否有缺陷?我一直处于黑暗中很长一段时间,而不是阅读关于MEF并尝试不同的建议,我已经将MEF添加到了我的解决方案中,并且正在进入代码中。它看起来像失败的部分是当它呼叫partManager.GetSavedImport()。出于某种原因,importCache为空,我不明白。一直到目前为止,它一直在查看部件(Window1)并试图解析两个导入的接口 - IError和IPlugin。我会期望它输入代码,查看其他程序集在​​相同的可执行文件夹中,然后检查它的出口,以便它知道如何解决导入...

我发现我的代码中有错误,当我修正它时,MEF例外情况发生了变化,并且也更加有用。它明确指出它找不到CandySettings的默认构造函数!而挖掘更多,我发现一个good post from Glenn Block讨论这一点。所以我需要完成阅读并看看他的解决方法是否能解决问题。我仍然会喜欢更多的答案,因为不知道解决方法是否正确。

回答

1

这篇文章真的有帮助。我之前没有看到这些信息,但它完全为我做了诀窍。

http://mindinthewater.blogspot.com/2010/01/using-mef-with-classes-which-take.html

基本上,我的问题是,我需要的值传递给构造函数。我之前的所有测试都涉及将接口传递给其他共享库,但就我而言,我只想传递几个字符串。我显然不想尝试在接口中包装这些字符串来传递POCO。

我第一次尝试解决这个不便之处,是尽我所能用默认构造函数做到最好。然后,我把它留给了开发人员记得调用Init()方法的命运。这显然是很糟糕的,但我仍想尝试一下。最后,它只是没有工作 - 这里的问题是,MEF想要解决进口和出口,但我的Init()方法不会被调用,直到构成零件之后......所以任何其他受抚养人该特定库的最终结果将是一个未真正初始化的库实例,因为Init()直到后期才会被调用。

无论如何,这个为构造函数参数导入字符串的技巧就像一个魅力。

+0

啊,所以*你*是我博客文章中的匿名评论者:-) – 2010-04-21 00:37:35

0

如果您包含您收到的错误消息,这将有所帮助。

但是,如果你使用左边的方法,我认为在你的Window1类上放置一个PartNotDiscoverableAttribute可能会解决这个问题。

问题是DirectoryCatalog将包含包含Window1的程序集,因此将从目录中提供可用的IError导出(如果您请求导出的值,则MEF将创建Window1的实例)。当您添加通过ComposeParts创建的Window1时,您正尝试向容器添加另一个IError导出。由于您的插件仅请求单个IError导出,因此当存在多个可用插件时它将不起作用。在Window1类中添加PartNotDiscoverableAttribute将防止它被包含在目录中。

+0

对不起,我忘了发布错误,但是我发布的错误可能是错误的。 :)事实证明,MEF错误告诉我,我*必须*使用无参数的构造函数。不过,在这两种情况下,我只有一个IError实现。 – Dave 2010-04-19 22:31:07

+0

@Dave如果您在其中添加了ImportingConstructorAttribute参数,您可以使用带有参数的构造函数,这是您在发布的代码中为Plugin完成的。 – 2010-04-20 00:51:17

+0

是的,我在一个例子中完成了。我在解释我所指的是什么时做得很差。我得到了这个错误,因为我没有默认构造函数,而其他构造函数没有用[ImportingConstructor]标记。然而,我见过的所有例子中,构造函数参数都是由MEF解决的其他接口,所以我感到困惑,因为我只想传递几个字符串。我不想为了支持MEF而做一些奇怪的包装。 – Dave 2010-04-20 01:48:41