2

我误解了继承的一些明显的东西。我创建了一个示例控制台应用程序,它有一些相互继承的接口和类。

使用工厂,我试图根据给定的密钥检索适当的服务。但是编译器说它不能将具体类添加到我要求的通用字典中。

这是我正在尝试做的事情:

给定一个工厂,通过键名获取服务。然后Search在此服务上执行该方法。

class Program
{
    static void Main(string[] args)
    {
        var animalFactory = new AnimalFactory();

        // Search for some fishes.
        var fishService = animalFactory.GetAnimalService("fish");
        var fishes = fishService.SearchForAnimals(new FishSearchOptions {ScalesType = "shiny green"});

        // Search for meows.
        var catService = animalFactory.GetAnimalService("cat");
        var kittyCats = catService.SearchForAnimals(new MamalSearchOptions {HairColour = "golden"});
    }
}

到目前为止,一切都很好?请注意,每个服务都可以接受它自己的特定搜索类作为输入参数。例如。aMamalService只能接受一个MamalSearchOptions类。

这里是工厂...

public class AnimalFactory
{
    private IDictionary<string, IAnimalService<IAnimal, IAnimalSearchOptions>> _animals;

    public AnimalFactory()
    {
        _animals = new Dictionary<string, IAnimalService<IAnimal, IAnimalSearchOptions>>
            {
                {"Cat", new MamalService() },
                {"Dog", new MamalService() },
                {"GoldFish", new FishService() }
            };
    }

    public IAnimalService<IAnimal, IAnimalSearchOptions> GetAnimalService(string name)
    {
        if (string.IsNullOrEmpty(name))
        {
            throw new ArgumentNullException("name");
        }

        return _animals[name];
    }
}

这是错误消息:

在此处输入图像描述

它不喜欢我尝试将服务插入(通用?)字典的方式。

现在,其他类和接口是什么样的?可以在这个要点中找到它们,而不是向这个线程发送垃圾邮件,这里。<-- 完整的 100% 回购。

有人可以解释我做错了什么并建议我需要正确做什么吗?我一直认为,如果超类继承自泛型集合的 Type,那么它们总是可以插入到泛型集合中。

4

1 回答 1

4

这仅在IAnimalService时才有效(例如声明为IAnimalService<out TAnimal, out TSearchOptions>)。

不幸的是,根据您的工厂界面,这似乎不起作用。例如,您有:

public class MamalService : IAnimalService<MamalItem, MamalSearchOptions>
{
    public SearchResult<MamalItem> SearchForAnimals(MamalSearchOptions searchOptions)
    {
        throw new NotImplementedException();
    }
}

public class FishService : IAnimalService<Fish, FishSearchOptions>
{
    public SearchResult<Fish> SearchForAnimals(FishSearchOptions searchOptions)
    {
        throw new NotImplementedException();
    }
}

如果编译器允许您的代码,则可能会发生以下情况:

var dict = new Dictionary<string, IAnimalService<IAnimal, IAnimalSearchOptions>> {
    { "Dog", new MammalService() }
};

IAnimalService<IAnimal, IAnimalSearchOptions> service = dict["Dog"];

// this would be legal given the type of service, but would clearly not 
// be correct for MammalService:
IAnimal animal = service.SearchForAnimals(new FishSearchOptions());

为了让这个设计工作,你可能会考虑IAnimalService只接受一个IAnimalSearchOptions作为它的参数而不是一个通用参数。然后你可以将 TAnimal 标记为一个输出参数,你会是协变的。当然,您也会失去类型安全性,因为您MammalService必须将输入IAnimalSearchOptions转换为MammalSearchOptions.

另一种常见的解决方案是拥有 2 个版本的接口,一个是通用版本,一个不是(如 IEnumerable 和 IEnumerable)非通用版本放弃了一些类型安全性,但在您上面显示的情况下更有用:

interface IAnimalService { IAnimal SearchForAnimals(IAnimalSearchOptions opts); }

interface IAnimalService<out TAnimal, in TOptions> : IAnimalService
    where TAnimal : IAnimal
    where TOptions : IAnimalSearchOptions {
    TAnimal SearchForAnimals(TOptions opts);
}

class MammalService : IAnimalService<Mammal, MammalSearchOptions>
{

    Mammal SearchForAnimals(MammalSearchOptions opts) { ... }

    IAnimal IAnimalService.SearchForAnimals(IAnimalSearchOptions opts)
    {
        return this.SearchForAnimals((MammalSearchOptions)opts);
    }
}

……

var dict = new Dictionary<string, IAnimalService> { "Dog", new MammalService() };
于 2013-07-18T00:04:46.583 回答