我知道从MEF2开始,MEF支持将开放的泛型类型组合为封闭的类型。我正试图从从添加到同一组合容器的两个不同程序集导出的类型中组合一个闭合类型,但我收到了ImportCardinalityMatchException。我对其中一个程序集使用约定,因为它不在我的控制之下。对于另一个,我使用了属性。
我不太确定如何表达我的问题,因为我发现泛型的术语相当令人困惑,但我希望在不显式实现自己的类、从Foo继承并为其提供FooUser类型参数的情况下编写新的封闭类型。我不知道这是我做这件事的方式有问题,还是与类型在不同程序集中有关。
在一个组件中,我有以下内容:
public class Foo<T> where T : Bar {}
public class Bar {}
在另一个组件中,我有以下内容:
[Export]
public class Bar2 : Bar {}
[Export]
public class Something
{
[ImportingConstructor]
public Something([Import(typeof(Foo<>))] Foo<Bar2> foo) {}
}
在我的注册码中,我做了以下操作:
var conventions = new RegistrationBuilder();
conventions.ForType(typeof(Foo<>)).Export();
var aggregateCatalog = new AggregateCatalog();
var catalog = new AssemblyCatalog(typeof(Foo<>).Assembly, conventions);
aggregateCatalog.Catalogs.Add(catalog);
catalog = new AssemblyCatalog(typeof(Something).Assembly);
aggregateCatalog.Catalogs.Add(catalog);
catalog = new AssemblyCatalog(typeof(Bar2).Assembly);
aggregateCatalog.Catalogs.Add(catalog);
var container = new CompositionContainer(aggregateCatalog, CompositionOptions.DisableSilentRejection);
var batch = new CompositionBatch();
batch.AddExportedValue(container);
container.Compose(batch);
后来我试着这样导出我的价值:
container.GetExportedValue<Something>();
异常:抛出:"未找到与约束匹配的导出:合同名称Foo(Bar2)RequiredTypeIdentity Foo(Bar2)"(System.ComponentModel.Composition.ImportCardinalityMatchException)一个系统。组件模型。作文引发ImportCardinalityMatchException:"未找到与约束匹配的导出:合同名称Foo(Bar2)RequiredTypeIdentity Foo(Bar2)">
我已经查看了我的约定实例,在容器中我有我的部分,即Foo{0}、Bar2和Something。我仍然收到系统。组件模型。作文但是ImportCardinalityMatchException。
我在更抽象的情况下看到过这样做,比如说,有IRepository的情况,但没有更具体的情况,也没有跨组件的项目。如有任何协助,我们将不胜感激。除非有什么帮助,否则我可能只会继承那些令人反感的类型,然后就这么做了
编辑:我只是建立了上面详细介绍的非常简单的例子,因为我在现实世界中的项目中实际上做了一些与我在这里不同的事情,我得到了不同的类似结果。我重命名了一些类型,使它们与我的简化示例保持一致。
这篇作文出现了一个作文错误。下面提供了根本原因。查看CompositionException。Errors属性以获取更详细的信息。
1) 未找到与约束匹配的导出:ContractName CompositionTestLibrary。Foo(CompositionTestLibrary2.Bar2)RequiredTypeIdentity CompositionTestLibrary。Foo(CompositionTestLibrary2.Bar2)
结果:无法设置导入"CompositionTest"。某物ctor(Parameter="foo",ContractName="CompositionTestLibrary.foo(CompositionTestLibrary 2.Bar2)")'在部件"CompositionTest"上。什么"。元素:成分测试。某物ctor(Parameter="foo",ContractName="CompositionTestLibrary.foo(CompositionTestLibrary 2.Bar2)")-->CompositionTest。Something-->AssemblyCatalog(Assembly="CompositionTest,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null")
结果:无法获取导出"CompositionTest"。Something(ContractName="CompositionTest.Something")"来自部件"CompositionTest。什么"。元素:成分测试。Something(ContractName="CompositionTest.Something")-->CompositionTest。Something-->AssemblyCatalog(Assembly="CompositionTest,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null")
在下面的行中,您不应该使用conventions
变量,因此您应该更改
catalog = new AssemblyCatalog(typeof(FooUser).Assembly, conventions);
至
catalog = new AssemblyCatalog(typeof(FooUser).Assembly);
在这里使用conventions
实际上不会从定义了FooUser
和Something
的程序集中导出任何内容,因此您将无法获得Something
的组合值。删除它将允许导出和合成Something
。
将约定传递到目录可以防止MEF使用类型约束关闭泛型类型。考虑以下类别:
[Export]
public class Foo<T> where T : Bar { }
[Export]
public class FooUnconstrained<T> { }
[Export]
public class Bar { }
关闭无约束泛型类型有效,无论是否通过RegistrationBuilder
:
using (var catalogue = new ApplicationCatalog(new RegistrationBuilder()))
using (var container = new CompositionContainer(catalogue))
{
Console.WriteLine(container.GetExport<FooUnconstrained<Bar>>().Value);
}
仅关闭约束的泛型类型有效而不使用RegistrationBuilder
:
using (var catalogue = new ApplicationCatalog())
using (var container = new CompositionContainer(catalogue))
{
Console.WriteLine(container.GetExport<Foo<Bar>>().Value);
}
当使用RegistrationBuilder
时,关闭约束泛型类型失败:
using (var catalogue = new ApplicationCatalog(new RegistrationBuilder()))
using (var container = new CompositionContainer(catalogue))
{
// Next line throws ImportCardinalityMismatchException:
Console.WriteLine(container.GetExport<Foo<Bar>>().Value);
}
这似乎是.net的一个错误。我在releaseKey=528040(.net-4.8预览)上遇到了这种行为。
无论如何,我个人建议不要使用传统的模型,因为它要求合成器了解所有的约定。这意味着,如果不手动组合它们的约定逻辑,就无法将使用不同约定的两个不同代码库组合在一起。也就是说,它引入了与属性模型不存在的紧耦合。