组合部件方法不起作用
本文关键字:不起作用 方法 组合部 | 更新日期: 2023-09-27 18:32:06
我有一个ITagger和一个IWpfTextViewMargin,两者都导出为MEF组件。我想在我的保证金代码中导入 ITagger,然后在该标记器中使用一些成员。
现在我尝试在 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的问题。我不知道为什么参数是这个。我试图将目录传递给它,没有例外,但导入也是空的。我还提到了调试 mef 失败,并认为导出的类具有正确的协定名称和导出类型标识。
在使用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核心编辑器服务,但我找不到哪个程序集导出它。有人知道吗?
或者有更好的解决方案吗?
试试 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
程序集中都可用,否则您需要为提供零件的程序集创建更多 AssemlbyCatalog,并将它们添加到 AggregateCatalog 中。