ComposeParts方法不起作用

时间:2012-04-25 07:10:33

标签: c# .net visual-studio-2010 mef vs-extensibility

我有一个ITagger和一个IWpfTextViewMargin,两者都被导出为MEF组件。我想在我的保证金代码中导入ITagger,然后使用Tagger中的一些成员。

现在我尝试在Margin类中使用ComponentContainer,然后导入IViewTaggerProvider。我使用了以下代码,可以在许多MEF教程中找到

[Import(typeof(IViewTaggerProvider))]
public IViewTaggerProvider vt_provider { get; set; }

var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(typeof(TestMargin).Assembly));
_container = new CompositionContainer(catalog);
//Fill the imports of this object
try
{
    this._container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
    System.Diagnostics.Trace.WriteLine(compositionException.Message);
}

和导出代码。

[Export(typeof(IViewTaggerProvider))]
[ContentType...

导出的类在另一个名称空间中定义,但是使用相同的程序集。

这里我遇到了ComposeParts(this)抛出ImportCardinalityMismatchException的问题。我不知道为什么参数 this 。我试图将目录传递给它,没有例外,但导入也是null。我还提到debug mef failures并认为导出的类具有正确的合同名称和导出类型标识。


使用Visual MEFx检查程序集并进行调试后,我发现可能是因为IViewTaggerProvider导入Visual Studio IClassificationTypeRegistryService,它也是MEF部分并导致拒绝IViewTaggerProvider。

[Primary Rejection]
 [Exception] System.ComponentModel.Composition.ImportCardinalityMismatchException: No valid exports were found that match the constraint '((exportDefinition.ContractName == "Microsoft.VisualStudio.Text.Classification.IClassificationTypeRegistryService") AndAlso (exportDefinition.Metadata.ContainsKey("ExportTypeIdentity") AndAlso "Microsoft.VisualStudio.Text.Classification.IClassificationTypeRegistryService".Equals(exportDefinition.Metadata.get_Item("ExportTypeIdentity"))))', invalid exports may have been rejected.

因此,一种解决方案是添加导出IClassificationTypeRegistryService的程序集。它是Visual Studio核心编辑器服务,但我无法找到哪个程序集导出它。谁知道这个?

还是更好的解决方案?

1 个答案:

答案 0 :(得分:1)

尝试使用VisualMEFx。这是一篇关于入门https://ihadthisideaonce.com/2012/02/22/getting-started-with-visual-mefx/的简短博客文章。启动并运行后,使用VisualMEFx加载TestMargin程序集,并查看是否从该程序集导出任何IViewTaggerProvider。

还要记住,ImportCardinalityMistmatch并不仅仅意味着缺少导出。它也可能意味着有太多可用的导出可以满足导入,MEF无法选择使用哪一个。因此,当您在VisualMEFx中检查您的构图时,请检查是否有太多。

此参数:

void Bootstrap()
{
  var catalog = new AggregateCatalog();
  catalog.Catalogs.Add(new AssemblyCatalog(typeof(TestMargin).Assembly));
  _container = new CompositionContainer(catalog);

 //Fill the imports of this object
 try
 {
    var objectToSatisfy = this;
    // var objectToSatifsy = new SomeOtherObjectWithImports();

    this._container.ComposeParts(objectToSatisfy);
 }
 catch (CompositionException compositionException)
 {
    System.Diagnostics.Trace.WriteLine(compositionException.Message);
 }
}

当您致电ComposeParts时,您将对象传递给该方法。 MEF将获取您传递的对象,并查看是否有任何需要满足的导入。如果它找到任何导入,它将在目录中查找并尝试满足它们。您可以将任何对象传递给ComposeParts方法。所以我稍微修改了您的示例代码以显示两个不同的选项。一种选择是创建一些需要满足的对象,然后将其提供给容器进行合成。这就是我在注释掉的行var objectToSatisfy = new SomeOtherObjectWithImports()中所做的。但通常的情况是,我们要编写的对象与调用ComposeParts的对象相同。所以我们不需要创建一个新对象来传递给容器,我们已经有了对象,我们只需要对它进行引用。在C#中,我们可以使用关键字this获取对当前对象实例的引用(在VB.NET中,关键字为Me)。因此,当我们想要在调用ComposeParts的同一对象上满足导入时,我们可以使用this引用作为ComposeParts的参数来实现。

ComposeParts方法的参数是参数数组。非正式地说,这只是意味着当你写container.ComposeParts(this)时,它被解释为你写了container.ComposeParts(new object[] { this })。在实践中,这意味着您可以一次将多个对象传递给MEF,如下所示:

container.ComposeParts(this, objectToSatifsy, thirdObjectToCompose);

如果调用ComposeParts的对象没有导入,那么您不应该使用this作为参数。而是创建一个要组合的类型的对象,并将其传递给方法。此外,除非您要编写的所有部分都在TestMargin程序集中可用,否则您需要为提供部件并将其添加到AggregateCatalog的程序集创建更多AssemlbyCatalog。