【问题标题】:ComposeParts method not workingComposeParts 方法不起作用
【发布时间】:2012-04-25 07:10:32
【问题描述】:

我有一个 ITagger 和一个 IWpfTextViewMargin,它们都作为 MEF 组件导出。我想在我的 Margin 代码中导入 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。我试图将 catalog 传递给它,没有例外,但导入也是空的。我还参考了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 核心编辑器服务,但我找不到哪个程序集导出它。有人知道吗?

或者有更好的解决方案吗?

【问题讨论】:

  • 如果您创建一个导入列表和导出列表,它会更容易提供帮助。我认为“消费”基本上是指[Import]ing
  • @jberger:也许我试过你说的。我更新了我的问题,似乎是一个新问题
  • Margin 班级的签名是什么?
  • @jberger:你说的签名是什么意思?
  • 它的相关因素、进口、出口等是什么?

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


【解决方案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 程序集中可用,否则您需要为确实提供这些部件的程序集创建更多 AssemlbyCatalogs 并将它们添加到您的 AggregateCatalog。

【讨论】:

  • 我会试试visualMEFx。但是你能解释一下为什么这个参数是 this 吗?
  • 而且由于我的宿主类不是导出类,因此它没有在 VisualMEFx 中列出。IViewTaggerProvider 组件使用 Rejection 导出,因为它导入了一个未在我的程序集中导出的服务。我猜是这样
  • 导入部件的类也将被列出。如果通过主机类,您的意思是包含 MEF 容器的类,那么是的,可能会列出也可能不会列出,这取决于该类是导入还是导出任何东西。我无法从发布的代码中看出。
  • 听起来 VisualMEFx 是在告诉您,您的提供程序具有其他依赖项,这些依赖项未由 TestMargin 程序集导出,这是您告诉 MEF 查找零件的唯一程序集。您需要向 AggregateCatalog 添加额外的 AssemblyCatalog。
  • 是的,主机类是带有容器的,并且只导入 IViewTaggerProvider。至于参数,你的解释似乎有道理,但是msdn把它当成要组合的属性对象数组,我还是有点糊涂。那么 ComposeParts 是做什么的呢?遍历容器中的目录,看看是否有任何可以满足第二个参数中的导入?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-25
  • 2016-01-07
  • 2016-01-11
  • 2015-01-09
相关资源
最近更新 更多