【问题标题】:Composing Open Generic Types with Closed Types in MEF 2在 MEF 2 中组合开放泛型类型和封闭类型
【发布时间】:2014-01-07 18:25:31
【问题描述】:

我了解,从 MEF 2 开始,MEF 支持将开放的泛型类型组合成封闭的类型。我正在尝试从添加到同一组合容器的两个不同程序集导出的类型中组合一个封闭类型,并且我收到 ImportCardinalityMismatchException。我正在对其中一个程序集使用约定,因为它不在我的控制之下。对于其他我使用了属性。

我不确定如何表达我的问题,因为我发现有关泛型的术语相当混乱,但我希望在不显式实现我自己的类、从 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.ImportCardinalityMismatchException) 引发了 System.ComponentModel.Composition.ImportCardinalityMismatchException:“未找到与约束匹配的导出: 合同名称 Foo(Bar2) 必填类型标识 Foo(Bar2)"

我查看了我的约定实例,并在容器中查看了我的部分,即 Foo{0}、Bar2 和 Something。但是,我仍然收到 System.ComponentModel.Composition.ImportCardinalityMismatchException。

我已经在更抽象的情况下看到过这种情况,比如有 IRepository,但没有更具体的东西,也没有跨越程序集的项目。任何帮助将不胜感激。除非有任何帮助,否则我可能会从有问题的类型继承并完成它。

编辑:我刚刚构建了上面详述的非常简化的示例,因为我在现实世界的项目中实际上正在做一些与我在这里不同的事情并且我有不同的相似结果。我已经重命名了一些类型以使它们与我的简化示例保持一致。

合成产生了单个合成错误。下面提供了根本原因。查看 CompositionException.Errors 属性以获取更多详细信息。

1) 未找到与约束匹配的导出: 合同名称 CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2) RequiredTypeIdentity CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2)

导致:无法在“CompositionTest.Something”部分设置导入“CompositionTest.Something..ctor (Parameter="foo", ContractName="CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2)")'。 元素:CompositionTest.Something..ctor (Parameter="foo", ContractName="CompositionTestLibrary.Foo(CompositionTestLibrary2.Bar2)") --> CompositionTest.Something --> AssemblyCatalog (Assembly="CompositionTest, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

导致:无法从“CompositionTest.Something”部分导出“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 变量,即定义了Foo&lt;T&gt; 的程序集吗?
  • 我是。在我的真实代码中,就像上面的示例一样,我将相同的 RegistrationBuilder 传递给每个目录。

标签: c# generics mef open-generics mef2


【解决方案1】:

在下面的行中你不应该使用conventions 变量,所以你应该改变

catalog = new AssemblyCatalog(typeof(FooUser).Assembly, conventions);

catalog = new AssemblyCatalog(typeof(FooUser).Assembly);

在此处使用conventions 实际上不会从定义了FooUserSomething 的程序集中导出任何内容,因此您将无法获得Something 的组合值。删除它将允许Something 被导出和合成。

【讨论】:

  • 不幸的是,事实并非如此。删除该参数没有任何作用。
【解决方案2】:

将约定传递给目录可防止 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 预览版)上遇到了这种行为。

无论如何,我个人建议不要使用传统模型,因为它要求合成器了解所有约定。这意味着如果不手动组合它们的约定逻辑,就无法将两个使用不同约定的不同代码库组合在一起。即,它引入了属性模型不存在的紧密耦合。

【讨论】:

猜你喜欢
  • 2010-12-16
  • 1970-01-01
  • 2011-07-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多