使用约定在MEF 2中使用默认构造函数和开放泛型 [英] Default constructor and open generics in MEF 2 using conventions

查看:83
本文介绍了使用约定在MEF 2中使用默认构造函数和开放泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在我的项目中使用MEF 2,我通常使用SimpleInjector,但是这次我想尝试MEF.我的主要问题是处理开放式泛型,这就是我到目前为止所得到的

I am trying to use MEF 2 in my project, I usually use SimpleInjector but this time I wanted to try MEF. My main problem is dealing with open generics, this is what i got so far

public interface ISetting {}
public class Setting : ISetting {}

public interface ILogger<TLog>
{
    TLog Fetch()
}

public class Logger<TLog> : ILogger<TLog>
{
    private ISetting settings;

    public Logger(ISetting settings)
    {
        this.settings = settings;
    }

    public TLog Fetch()
    {
        return default(TLog);
    }
}

现在是我要做的容器部分

Now for the container part I do

var conventions = new ConventionBuilder();

conventions.ForType<Setting>()
           .Export<ISetting>()
           .Shared();

conventions.ForType(typeof(Logger<>))
           .Export(t => t.AsContractType(typeof(ILogger<>)))
           .Shared();

var configuration = new ContainerConfiguration()
        .WithAssembly(typeof(Program).Assembly,conventions);

using (var container = configuration.CreateContainer)
{
    var export = container.GetExport<ILogger<object>>(); //Exception :(
}

当尝试检索导出时,出现此异常

When it's trying to retrieve the export I am getting this exception

在类型'MEFTest.Logger`1 [System.Object]'上未找到导入构造函数.

No importing constructor was found on type 'MEFTest.Logger`1[System.Object]'.

如果我从Logger类中删除构造函数,则容器构造封闭的泛型就好了.我98%确信问题与构造函数有关,但我觉得我在这里遗漏了一些东西

If I remove the constructor from the Logger class the container construct the closed generic just fine. I am 98% sure that the problem is related with the constructors but I feel I am missing something here

通过阅读,我实际上发现有2个版本的MEF,一个是Nuget软件包,另一个是.NET40附带的版本,我正在使用的是Nuget软件包.我进行了一些重构,以使用.NET40附带的版本.

Edit 1: Doing some reading I have actually discovered that there are 2 versions of MEF, one that is a Nuget package and another one that ships with .NET40, the one that I am using is the Nuget package. I did some refactoring to use the one that ships with .NET40

除了创建和使用容器的部分之外,所有代码都是相同的

All the code is the same except for the part that creates and use the container

var category = new AssemblyCatalog(Assembly.GetExecutingAssembly(), conventions);

using (var container = new CompositionContainer(category))
{
    var logic = container.GetExport<ILogger<int>>().Value; //Lazy Initialization O.o
    var test = logic.Fetch();

    // the rest of the code …
}

这有效:)很好,所以我肯定在Nuget软件包的版本中缺少了一些东西

This works :) just fine so definitely I am missing something in the version of the Nuget package

删除了 WithAssembly 方法中通用部分的自动检测" 后,代码开始工作,此处代码被重构了

Edit 2: With the removal of the "auto-detection" of the generic parts in the WithAssembly method the code works, here is the code refactored

约定部分:

var conventions = new ConventionBuilder();

conventions.ForType<Setting>()
           .Export<ISetting>();

conventions.ForType<Logger<int>>()
           .Export<ILogger<int>>();

容器部分:

var types = new Type[] { typeof(Setting), typeof(Logger<int>) };

var configuration = new ContainerConfiguration()
        .WithParts(types, conventions);

using (var container = configuration.CreateContainer())
{
    var logic = container.GetExport<ILogger<int>>();
    var test = logic.Fetch();

    // the rest of the code …
}

我将特定类型更改为 integer .执行 Fetch()时,它会正确返回0作为int的默认值

I changed the specific type to integer.When it executes Fetch() it returns correctly 0 as the default value for int

有趣的部分是为什么泛型的自动检测" 强制标记构造函数的原因

The interesting part is why the "auto-detection" of the generics force the constructor to be marked

我认为自动检测" 部分不是这里的过错,因为我已经尝试过了

Edit 3: I think the "auto-detection" part is not the one at fault here because I have tried this

var conventions = new ConventionBuilder();

conventions.ForType<Setting>()
           .Export<ISetting>();

conventions.ForType(typeof(Logger<>))
           .Export(t => t.AsContractType(typeof(ILogger<>)));

var types = new Type[] { typeof(Setting), typeof(Logger<>) };

var configuration = new ContainerConfiguration()
        .WithParts(types, conventions);

using (var container = configuration.CreateContainer())
{
    var logic = container.GetExport<ILogger<int>>();
    var test = logic.Fetch();

    // the rest of the code …
}

使用该代码,我回到正题,因为它会产生相同的异常,它会强制使用标记属性

With that code I am back to square one because it produces the same exception, it enforces the use of the marking attribute

:实际的MEF项目已转到 System.Composition 下的 CoreFx GitHub 页面.我参加了单元测试,并在 RegistrationBuilderCompatibilityTest 第40-58行

Edit 4: The actual MEF project has gone to the CoreFx GitHub page under System.Composition. I went to the unit tests and in the RegistrationBuilderCompatibilityTest lines 40-58

public interface IRepository<T> { }

public class EFRepository<T> : IRepository<T> { }

[Fact]
public void ConventionBuilderExportsOpenGenerics()
{
    var rb = new ConventionBuilder();

    rb.ForTypesDerivedFrom(typeof(IRepository<>))
      .Export(eb => eb.AsContractType(typeof(IRepository<>)));

    var c = new ContainerConfiguration()
        .WithPart(typeof(EFRepository<>), rb)
        .CreateContainer();

    var r = c.GetExport<IRepository<string>>();
}

在没有默认构造函数的情况下,他们从未进行过测试

They never tested it without the default constructor

结果:我最终在以下位置打开了问题并在CoreFx Github页面上提交了 PR 并已修复该错误

Results: I end up opening an issue on the CoreFx Github page and submitted a PR with a fix for the bug

推荐答案

直到他们合并我的 PR 并发布修正了错误的版本,我建议使用 Edit 2 上的解决方案.我认为这是实现所需功能的最少介入方式

Until they merge my PR and release a version with the bug fixed I recommend going with the solution on Edit 2. I think it is the least intrusive way of achieving the functionality required

基本上,您需要使用 CLOSED 泛型类型构建约定,并使用这些封闭的泛型创建集合.在容器中,使用 WithParts 方法以及已定义的惯例,有关代码段,请参见编辑2 .

Basically you need to build conventions with your CLOSED generic types and create a collection with these closed generics. In the container use the WithParts method along with the conventions that were defined, see Edit 2 for code snippet

更新

我的 PR 已合并,现在支持此功能.它将于2017年4月30日之前发布在 corefx 2.0 中.

My PR has been merged and this functionality is now supported. It will be released in corefx 2.0 due by April 30, 2017

这篇关于使用约定在MEF 2中使用默认构造函数和开放泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆