MEF 2,Generic Import with implementation class

时间:2015-09-26 13:10:58

标签: c# generics mef

我正在尝试利用Generics和MEF解决方案的优势,但是我正在努力让事情得到注册。 (使用MEF 2,.Net 4.51)。

以下是我想要使用的类和接口的简化版本:

public interface IAnimal
{
    string Speak();
}

public interface IAnimalCatcher<T> where T : IAnimal
{
    string WhatICatch();
    T AnimalCaught { get; set; }
}

[Export(typeof(IAnimal))]
public class Dog : IAnimal
{
    public string Speak()
    {
        return "Woof";
    }
}

//[Export(typeof(IAnimalCatcher<IAnimal>))]
//[Export(typeof(IAnimalCatcher<Dog>))]
public class DogCatcher: IAnimalCatcher<Dog>
{
    public string WhatICatch()
    {
        return "Dogs";
    }

    public Dog AnimalCaught { get; set; }
}

和执行组成的代码:

 public class Program
    {

        private CompositionContainer _container;

        [Import(typeof(IAnimal))]
        public IAnimal TheAnimal;


        [Import(typeof(IAnimalCatcher<>))]
        public IAnimalCatcher<IAnimal> TheAnimalCatcher;

         public Program()
        {
            var catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));

            _container = new CompositionContainer(catalog);
            this._container.ComposeParts(this);

        }

    }

我无法正确导出和导入Dog Class。我尝试了几种没有成功的组合(在课程上面评论过)。

错误如下:

  

System.ComponentModel.Composition.ChangeRejectedException是   未处理的消息=组成保持不变。变化   由于以下错误被拒绝:组成   产生了单一的构图错误。根本原因如下。   查看CompositionException.Errors属性以获取更详细的信息   信息。

     

1)没有找到符合约束条件的导出:     ContractName MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)     RequiredTypeIdentity MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)

     

导致:无法设置导入'MEFGeneric.Program.TheAnimalCatcher(ContractName =“MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)”)'on   部分'MEFGeneric.Program'。元件:   MEFGeneric.Program.TheAnimalCatcher   (ContractName =“MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)”) - &gt;   MEFGeneric.Program

请注意,IAnimalCatcher<IAnimal>会注册,但这不会让我限制狗捕手。

有没有办法通过导入解决这个问题,或者我的设计存在缺陷,我是否应该以不同的方式实施DogCatcher?

1 个答案:

答案 0 :(得分:2)

MEF正在寻找导出IAnimalCatcher<IAnimal>的类型。您DogCatcher导出IAnimalCatcher<Dog>,因此不适合候选人。将DogCatcher的导出更改为IAnimalCatcher<IAnimal>不是解决方案,因为您无法将IAnimalCatcher<Dog>分配给IAnimalCatcher<IAnimal>

如果您能够进行分配,则可以通过设置AnimalCaught类型的DogCatcher属性的值,将Cat IAnimalCatcher.AnimalCaught分配给IAnimal }。您不希望DogCatcher捕获Cat,因此编译器将不允许它。

解决方案是更改DogCatcher,使其实现IAnimalCatcher<IAnimal>而不是IAnimalCatcher<Dog>

[Export(typeof(IAnimalCatcher<IAnimal>))]
public class DogCatcher: IAnimalCatcher<IAnimal>
{
    public string WhatICatch()
    {
        return "Dogs";
    }

    public IAnimal AnimalCaught { get; set; }
}

这种不幸的副作用是你现在允许任何人修改DogCatcher抓住的动物来说Cat

但还有另一种选择。如果您可以从AnimalCaught移除设置器,则可以使IAnimal类型参数协变(out修饰符):

public interface IAnimalCatcher<out T> where T : IAnimal
{
    string WhatICatch();
    T AnimalCaught { get; }
}

这使得IAnimalCatcher<Dog>IAnimalCatcher<IAnimal>的分配合法:

[Export(typeof(IAnimalCatcher<IAnimal>))]
public class DogCatcher: IAnimalCatcher<Dog>
{
    public string WhatICatch()
    {
        return "Dogs";
    }

    public Dog AnimalCaught { get; private set; }
}