带有实现类的泛型导入

本文关键字:泛型 导入 实现 | 更新日期: 2023-09-27 18:14:50

我试图利用泛型和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类正确导出和导入。我已经尝试了几个组合没有成功(评论上面的类)。

错误如下:

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

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)")- - ->MEFGeneric。项目

请注意,IAnimalCatcher<IAnimal>将注册,但这并不能让我将捕狗器限制为狗。

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

带有实现类的泛型导入

MEF正在寻找导出IAnimalCatcher<IAnimal>的类型。你有DogCatcher输出IAnimalCatcher<Dog>,所以这不是一个合适的候选。更改DogCatcher的导出为IAnimalCatcher<IAnimal>不是一个解决方案,因为您不能将IAnimalCatcher<Dog>分配给IAnimalCatcher<IAnimal>

如果你能够进行分配,那么你可以通过设置IAnimal类型的IAnimalCatcher.AnimalCaught属性的值将DogCatcher中的AnimalCaught分配给Cat。你不希望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; }
}