C# 一个新的MEF错误I';“我以前没见过——”;导出不可分配给类型…“;

C# 一个新的MEF错误I';“我以前没见过——”;导出不可分配给类型…“;,c#,wpf,visual-studio-2010,.net-4.0,mef,C#,Wpf,Visual Studio 2010,.net 4.0,Mef,今天我很惊讶地发现了这个错误,因为这是我以前从未遇到过的错误。代码中的一切看起来都很好,所以我做了一些搜索。前面的问题和他们各自的答案没有帮助 当海报确保他的装配参考一致时,问题就解决了。我现在没有这个问题,因为我目前正在引用解决方案中的另一个项目 当海报被指示使用ImportMany时,问题就解决了,但我已经在使用它(我认为也是正确的)尝试加载多个插件 当海报意识到平台目标不匹配时,问题得到解决。我已经完成了我的项目,以确保一切都以x86为目标 这就是我要做的。我有一个插件,它拥有与设备的

今天我很惊讶地发现了这个错误,因为这是我以前从未遇到过的错误。代码中的一切看起来都很好,所以我做了一些搜索。前面的问题和他们各自的答案没有帮助


当海报确保他的装配参考一致时,问题就解决了。我现在没有这个问题,因为我目前正在引用解决方案中的另一个项目

当海报被指示使用ImportMany时,问题就解决了,但我已经在使用它(我认为也是正确的)尝试加载多个插件

当海报意识到平台目标不匹配时,问题得到解决。我已经完成了我的项目,以确保一切都以x86为目标


这就是我要做的。我有一个插件,它拥有与设备的连接。我可能还需要能够与其他插件共享该连接。我认为最干净的方法是创建一个接口,允许从属插件请求自己与设备的连接。我们就叫它
iconnectionsharr
。如果从属插件不需要借用此连接,并且有自己的连接,那么它应该使用自己的
iconnectionsharr
实现来连接到设备

我的“主”插件(拥有设备连接的插件)实现了
IConnectionSharer
。它还通过ExportAttribute导出此属性

我的“从属”插件程序集定义了一个类,该类还实现并导出
iconnectionsharr

当应用程序加载时,我的slave插件通过MEF枚举所有
IConnectionSharer
s并将它们存储在
IEnumerable
中。它是这样做的:

[ImportMany]
public IEnumerable<IConnectionSharer> AllSharedConnections { get; set; }
“从”插件:

型号:

[Export(typeof(Model))]
public class Model
{
    [ImportMany(typeof(IConnectionSharer))]
    private IEnumerable<IConnectionSharer> AllSharedConnections { get; set; }
    ...
}
但是在部件组合过程中,我得到一个错误:export'Company.MasterPlugin(ContractName=“IConnectionSharer”)“不可分配给类型'IConnectionSharer'

错误消息本身似乎很清楚——好像MEF认为我的主插件不是从IConnectionSharer继承的。。。但确实如此!有人能提出进一步的调试策略吗?我将开始一步一步通过MEF源的痛苦过程

更新

这是一条有趣的线索——如果在清除我的输出文件夹并重建解决方案后,我删除了“主”插件(这样“从”插件将使用自己的IConnectionSharer对象),我的应用程序加载正常,并且我的从插件也按预期运行。如果我把主插件放回plugins文件夹,我会再次遇到MEF组合问题

我还认为我应该尝试使用惰性实例化,看看这是否有任何效果。结果有点令人吃惊。MEF抱怨此错误:无法填充集合“AllSharedConnections”,因为它未实现ICollection或是只读的。如果集合不是
IEnumerable
或T[],则它必须实现ICollection,并且必须预先初始化,或者可以使用默认构造函数写入


嗯?显然,AllSharedConnections是一个
IEnumerable
,那么为什么MEF会抱怨呢?

出于好奇,请检查包含IConnectionSharer类型的程序集是否在调试器下加载了两次。程序集可能会在流程中的多个上下文中加载,在这种情况下,如果两种类型从加载的程序集的不同版本引用,则应该相同的两种类型似乎会不同

您是否有可能拥有两个不同版本的合同程序集,并且每个版本都正在加载?一个可以来自可执行路径,另一个来自插件路径

这些可能有助于:


您的输出文件夹中很可能有旧版本的程序集,例如重命名后。通常这不是问题,因为没有其他程序集引用此旧程序集。但是,使用MEF,只需将程序集存在应用程序文件夹中,就可以为合成拾取程序集

清理输出文件夹,重新构建,然后查看问题是否消失


edit:由于在清理输出文件夹时问题并没有消失,我的下一个猜测是您有两个
IConnectionSharer
声明,或者您正在将相同的代码编译到两个不同的程序集中。这将导致两个
IConnectionSharer
接口具有相同的名称,但具有不同的标识。

我找到了导致问题的原因,但我不确定解决问题的最佳方法。我现在将发布解决方案,但随后将发布一个新问题,因为它实际上与MEF无关

如前所述,我有一个通过软件狗连接到电脑的设备。我希望能够与其他设备共享该加密狗,但加密狗的第三方软件不允许同时连接到它

我的意图是允许“从”插件从“主”连接“借用”连接,并通过一个我称之为
iconnectionsharr
的接口来实现。好消息是我已经确认了它的工作原理——我只需要找出我的MEF错误

通过使用C#DLL调用其C DLL(使用C#包装类通过PInvoke调用C DLL),可以实现与加密狗的接口。然而,实际上我有两个这样的加密狗,但是第三方库不允许在一台计算机上有两个。我可以通过创建另一个C#DLL包装副本作为一个完全独立的程序集来欺骗它。这个程序集只是有到我的另一个C#DLL中的.cs文件的链接,但是有一个不同的C#wrapper类副本。我修改了这个副本来调用他们的C DLL的另一个副本,以强制它以不同的速度加载
[PartCreationPolicy(CreationPolicy.Shared)]
[Export(typeof(Interface1))]
public class SlavePlugin : Interface1
{
    private Model _model { get; set; }
    private ViewModel _viewmodel { get; set; }

    [ImportingConstructor]
    public SlavePlugin( [Import] Model model) 
    {
        _model = model;
        _viewmodel = new ViewModel( model);
    }
}
[Export(typeof(Model))]
public class Model
{
    [ImportMany(typeof(IConnectionSharer))]
    private IEnumerable<IConnectionSharer> AllSharedConnections { get; set; }
    ...
}
[Export(typeof(IConnectionSharer))]
public class PrivateConnection : IConnectionSharer
{
    ...
}