2015-09-26 61 views
1

我正在尝试利用泛型与MEF解决方案的好处,但是我正在努力使事情注册。 (Am正在使用MEF 2,.Net 4.51)。MEF 2,泛型导入与实现类

这里是我的类和接口的简化版本,我想工作:

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); 

     } 

    } 

我不能让狗类以正确导出和导入。我尝试过几次没有成功的组合(评论上面的类)。

误差如下:

System.ComponentModel.Composition.ChangeRejectedException是 未处理消息=的组合物保持不变。 的更改由于以下错误而被拒绝:组合 产生了单个组合错误。根源在下面提供。 查看CompositionException.Errors属性以获取更详细的 信息。

1)出口没有发现匹配的约束: ContractName MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal) RequiredTypeIdentity MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)

,导致:无法设置进口“MEFGeneric.Program。 零件'MEFGeneric.Program'上的动画捕捉器(ContractName =“MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)”)'。元素: MEFGeneric.Program.TheAnimalCatcher (ContractName = “MEFGeneric.IAnimalCatcher(MEFGeneric.IAnimal)”) - > MEFGeneric.Program

注意IAnimalCatcher<IAnimal>将注册,但是,这并不让我限制狗捕手给狗。

有没有办法通过导入来解决这个问题,还是我的设计有缺陷,我应该以不同的方式实现DogCatcher?

回答

2

MEF正在寻找一种出口IAnimalCatcher<IAnimal>的类型。你有DogCatcher出口IAnimalCatcher<Dog>,所以这不是一个合适的候选人。将DogCatcher的出口更改为IAnimalCatcher<IAnimal>不是解决方案,因为您无法将IAnimalCatcher<Dog>指定为IAnimalCatcher<IAnimal>

如果能够进行分配,那么你可以通过设置IAnimal类型的IAnimalCatcher.AnimalCaught属性值分配的DogCatcherAnimalCaughtCat。你不希望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删除setter方法可以使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; } 
} 
+1

,解决我的问题,现在也花了很多时间阅读Covariant和Contravariant接口。 (见http://stackoverflow.com/questions/2719954/understanding-covariant-and-contravariant-interfaces-in-c-sharp)就是一个很好的例子。 – Spevy