简体   繁体   English

MEF 2无法导入通用接口的通用实现

[英]MEF 2 can't import generic implementation of generic interface

I'm using latest MEF 2 preview from Codeplex homepage , and it's supposed to add open-generics support. 我正在使用Codeplex主页上的最新MEF 2预览,并且应该添加开放泛型支持。 It does, but in this specific case, MEF fails to compose generic implementation of generic interface: 可以,但是在这种特定情况下,MEF无法组成通用接口的通用实现:

public interface IOuter
{
    IInner Value { get; }
}

[Export(typeof(IOuter))]
public class MyOuter : IOuter
{
    [ImportingConstructor]
    public MyOuter(InnerGenericClass<string, int> value)
    {
        this.Value = value;
    }

    public IInner Value { get; private set; }
}

public interface IInner
{
    void Say();
}
public interface IGenericInner<T, K> : IInner
{
    // something else here
}

[Export(typeof(IGenericInner<,>))]
public class InnerGenericClass<T, K> : IGenericInner<T, K>
{
    public void Say()
    {
        Console.WriteLine("{0}, {1}", typeof(T), typeof(K));
    }
}

class Startup
{
    public void CatalogSetup()
    {
        var catalog = new AggregateCatalog(
            new AssemblyCatalog(Assembly.GetExecutingAssembly())
            );
        var container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);

        var batch = new CompositionBatch();

        container.Compose(batch);

        var outer = container.GetExportedValue<IOuter>();
        outer.Value.Say();
    }
}

Here's CompositionExpection : 这是CompositionExpection

The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) No exports were found that match the constraint: 
    ContractName    ConsoleApplication1.InnerGenericClass(System.String,System.Int32)
    RequiredTypeIdentity    ConsoleApplication1.InnerGenericClass(System.String,System.Int32)

Resulting in: Cannot set import 'ConsoleApplication1.MyOuter.Value (ContractName="ConsoleApplication1.InnerGenericClass(System.String,System.Int32)")' on part 'ConsoleApplication1.MyOuter'.
Element: ConsoleApplication1.MyOuter.Value (ContractName="ConsoleApplication1.InnerGenericClass(System.String,System.Int32)") -->  ConsoleApplication1.MyOuter -->  AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Resulting in: Cannot get export 'ConsoleApplication1.MyOuter (ContractName="ConsoleApplication1.IOuter")' from part 'ConsoleApplication1.MyOuter'.
Element: ConsoleApplication1.MyOuter (ContractName="ConsoleApplication1.IOuter") -->  ConsoleApplication1.MyOuter -->  AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Same exception is thrown even when I move importing of InnerGenericClass to attribute of MyOuter.Value : 即使我将InnerGenericClass的导入移至MyOuter.Value的属性, 也会引发相同的异常:

[Export(typeof(IOuter))]
public class MyOuter : IOuter
{
    [Import(typeof(InnerGenericClass<string, int>))]
    public IInner Value { get; private set; }
}

What is weird, is that, it does work , when I change import type to IGenericInner : 奇怪的是,当我将导入类型更改为IGenericInner时,它确实起作用了

[Export(typeof(IOuter))]
public class MyOuter : IOuter
{
    [ImportingConstructor]
    public MyOuter(IGenericInner<string, int> value)
    {
        this.Value = value;
    }

    public IInner Value { get; private set; }
}

What is even weirder, is that, it does not work , when importing via attribute. 甚至更奇怪的是,当通过属性导入时,它不起作用

Summary: I can't use generic interface to import object to Value property, because there could be more implementations of IGenericInner interface (and also I want to import a specific implementation, but that's not important). 简介:我不能使用通用接口将对象导入Value属性,因为可能会有IGenericInner接口的更多实现(而且我想导入特定的实现,但这并不重要)。

I hope I won't have to bypass MEF altogether in this case. 我希望在这种情况下,我不必完全绕过MEF。

Cause your exporting the interface IGenericInner<> but want to import the specific class InnerGenericClass MEF does not find the correct part. 使您导出接口IGenericInner <>,但要导入特定的类InnerGenericClass MEF找不到正确的部分。 You can export and import the specific class or create two exports of InnerGenericClass<> this way: 您可以通过以下方式导出和导入特定的类,或创建两次InnerGenericClass <>的导出:

[Export(typeof(IGenericInner<,>))]
[Export(typeof(InnerGenericClass<,>))]
public class InnerGenericClass<T, K> : IGenericInner<T, K> {
    public void Say() {
        Console.WriteLine("{0}, {1}", typeof(T), typeof(K));
    }
}

I just tested this in a VS .NET 4.5 project and it works. 我刚刚在VS .NET 4.5项目中对此进行了测试,并且可以正常工作。 Btw. 顺便说一句。 MEF 2 is already released in .NET 4.5 - If possible I recommend using System.ComponentModel.Composition.dll part of the framework not the preview version. .NET 4.5中已经发布了MEF 2-如果可能,我建议使用框架的System.ComponentModel.Composition.dll部分而不是预览版本。

UPDATE : A third solution (which will work with the Preview Version 5) could be to use additionally a string contract name. 更新 :第三个解决方案(将与预览版5一起使用)可能是另外使用字符串协定名称。 I personally try to avoid this cause of the ugly syntax, but ok. 我个人尝试避免这种语法丑陋的原因,但是可以。 Code will looks like this: 代码将如下所示:

[Export(typeof(IOuter))]
public class MyOuter : IOuter {
    [ImportingConstructor]
    public MyOuter([Import("MySpecialInnerGenericClass", typeof(IGenericInner<,>))]InnerGenericClass<string, int> value) {
        this.Value = value;
    }

    public IInner Value { get; private set; }
}
[Export("MySpecialInnerGenericClass", typeof(IGenericInner<,>))]
public class InnerGenericClass<T, K> : IGenericInner<T, K> {
    public void Say() {
        Console.WriteLine("{0}, {1}", typeof(T), typeof(K));
    }
} 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM