简体   繁体   English

无法解决MEF导入问题

[英]Having trouble getting MEF imports to be resolved

This is sort of a continuation of one of my earlier posts, which involves the resolving of modules in my WPF application. 这是我以前的一篇文章的延续,其中涉及WPF应用程序中模块的解析。 This question is specifically related to the effect of interdependencies of modules and the method of constructing those modules (ie via MEF or through new ) on MEF's ability to resolve relationships. 这个问题特别涉及模块相互依赖性的影响以及构造这些模块的方法(即通过MEF或通过new )对MEF解决关系的能力的影响。

I have tried two approaches: 我尝试了两种方法:

  • left approach: the App implements IError 左方法:应用程序实现IError
  • right approach: the App has a member that implements IError 正确的方法:应用程序具有实现IError的成员

Left approach 左进

My code behind looked like this (just the MEF-related stuff): 我后面的代码如下所示(仅仅是与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
{
    ...
}

Right-side approach 右侧方法

Basically the same as the left-side approach, except that I created a class that inherits from IError in the same assembly as Window1. 基本上与左侧方法相同,除了我在与Window1相同的程序集中创建了一个从IError继承的类。 I then used an [Import] to try to get MEF to resolve that for me. 然后,我使用[导入]尝试让MEF为我解决该问题。

Can anyone explain how the two ways I have approached MEF here are flawed? 谁能解释我在这里联系MEF的两种方式有何缺陷? I have been in the dark for so long that instead of reading about MEF and trying different suggestions, I've added MEF to my solution and am stepping into the code. 我已经呆了很长时间了,以至于没有阅读MEF并尝试其他建议,而是将MEF添加到了解决方案中,并着手编写代码。 The part where it looks like it fails is when it calls partManager.GetSavedImport() . 看起来失败的部分是当它调用partManager.GetSavedImport() For some reason, the importCache is null, which I don't understand. 由于某种原因,importCache为null,我不理解。 All the way up to this point, it's been looking at the part (Window1) and trying to resolve two imported interfaces -- IError and IPlugin. 到目前为止,一直在研究零件(Window1)并尝试解析两个导入的接口-IError和IPlugin。 I would have expected it to enter code that looks at other assemblies in the same executable folder, and then check it for exports so that it knows how to resolve the imports... 我希望它在同一可执行文件夹中输入可查看其他程序集的代码,然后检查其是否导出,以便它知道如何解析导入...

I had found a mistake in my code, and when I fixed it, the MEF exception changed, and was also more useful. 我在代码中发现了一个错误,当我修复它时,MEF异常发生了变化,并且更加有用。 It clearly pointed out that it couldn't find a CandySettings default constructor! 它明确指出它找不到CandySettings的默认构造函数! And digging more, I found a good post from Glenn Block that discusses this. 进一步挖掘,我在Glenn Block上找到了一篇很好的帖子,对此进行了讨论。 So I need to finish reading it and see if his workaround will do the trick or not. 因此,我需要完成阅读,看看他的解决方法是否可以解决问题。 I would still appreciate more answers, since there's no telling if the workaround is the right thing to do or not. 我仍然希望获得更多答案,因为没有人知道解决方法是否正确。

This post really helped. 这篇文章确实有帮助。 I hadn't seen this information before, but it totally did the trick for me. 我以前没有看过这些信息,但是这完全帮了我大忙。

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

Basically, my problem was that I needed to pass values to the constructor. 基本上,我的问题是我需要将值传递给构造函数。 All of my past tests involved passing interfaces to other shared libraries, but in my case, I just wanted to pass a couple of strings. 我过去的所有测试都涉及将接口传递给其他共享库,但就我而言,我只想传递几个字符串。 I obviously didn't want to try to wrap these strings in an interface just to pass POCOs. 我显然不想将这些字符串包装在接口中只是为了传递POCO。

My first attempt in getting around this inconvenience was to do the best I could with the default constructor. 为了避免这种不便,我的第一个尝试是尽我所能使用默认构造函数。 I then left it up to fate that a developer would remember to call the Init() method. 然后我把它留给命运,让开发人员记住要调用Init()方法。 This was bad for obvious reasons, but I wanted to try it out anyway. 由于明显的原因,这很糟糕,但是我还是想尝试一下。 In the end, it just didn't work -- the problem here is that MEF wants to resolve imports and exports, but my Init() method wouldn't get called until after composing the parts... so any other dependents of that particular library would end up with a not-truly-initialized instance of the library since Init() won't get called until later. 最后,它只是行不通-这里的问题是MEF想解决进出口问题,但是直到组成这些部分之后 ,我的Init()方法才被调用...所以该对象的任何其他依赖项由于Init()直到稍后才会被调用,所以特定的库最终会以未真正初始化的库实例结束。

Anyhow, this trick of importing strings for the constructor parameters worked like a charm. 无论如何,这种为构造函数参数导入字符串的技巧就像一个魅力。

It would help if you would include the error message that you are getting. 如果您要包含所收到的错误消息,这将有所帮助。

However, if you go with the left approach, I think putting a PartNotDiscoverableAttribute on your Window1 class may fix the problem. 但是,如果您采用左手方法,我认为在Window1类上放置PartNotDiscoverableAttribute可能会解决此问题。

The issue is that the DirectoryCatalog is going to include the assembly that includes Window1, so there is going to be an IError export available from the catalog (and MEF would create an instance of Window1 if you requested that export's value). 问题在于DirectoryCatalog将包含包含Window1的程序集,因此目录中将提供IError导出(如果您请求导出的值,MEF将创建Window1的实例)。 When you add the Window1 you created via ComposeParts, you are trying to add another IError export to the container. 当您添加通过ComposeParts创建的Window1时,您试图将另一个IError导出添加到容器中。 Since your plugin is only requesting a single IError export, it won't work when there is more than one available. 由于您的插件仅请求单个IError导出,因此当有多个可用时,它将无法正常工作。 Adding the PartNotDiscoverableAttribute on the Window1 class will prevent it from being included in the catalog. 在Window1类上添加PartNotDiscoverableAttribute将防止其包含在目录中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM