简体   繁体   English

转换 collections 中使用的 generics?

[英]Converting generics used in collections?

Let's say I want to create diet plans for pet owners to keep their pets healthy and I have the following classes:假设我想为宠物主人制定饮食计划以保持宠物健康,我有以下课程:

// Pets
public class Pet { ... }
public class Dog : Pet { ... }
public class Cat : Pet { ... }

// Meals and diets
public class Meal<T> : ICollection<T> where T : Pet
{
    ...
    private List<T> allowedPets { get; set; } = new List<T>();
    ...
}
public class Diet<T> : ICollection<Meal<T>> where T : Pet
{
    ...
    private List<Meal<T>> dietMeals { get; set; } = new List<Meal<T>>();
    ...
}

While I could have a list of pets that can follow a certain diet, rather than a list of pets that are allowed to have certain meals, this is just an example.虽然我可以有一份可以遵循某种饮食的宠物清单,而不是一份允许吃某些食物的宠物清单,但这只是一个例子。 Either way, I could make some arbitrary diets like these to use them in some sort of application.无论哪种方式,我都可以制作一些像这样的任意饮食,以便在某种应用程序中使用它们。

// Dogs and their diets
Dog labrador = new Dog() { ... };
Dog dalmatian = new Dog() { ... };
Meal<Dog> mediumDogBreakfast = new Meal<Dog>(...) { labrador, dalmatian };
Meal<Dog> mediumDogLunch = new Meal<Dog>(...) { labrador, dalmatian };
Meal<Dog> mediumDogDinner = new Meal<Dog>(...) { labrador, dalmatian };
Diet<Dog> mediumDogDiet = new Diet<Dog>()
{
    mediumDogBreakfast,
    mediumDogLunch,
    mediumDogDinner
};

// Cats and their diets
Cat siamese = new Cat() { ... };
Cat sphynx = new Cat() { ... };
Meal<Cat> orientalCatBreakfast = new Meal<Cat>(...) { siamese, sphynx };
Meal<Cat> orientalCatLunch = new Meal<Cat>(...) { siamese, sphynx };
Meal<Cat> orientalCatDinner = new Meal<Cat>(...) { siamese, sphynx };
Diet<Cat> orientalCatDiet = new Diet<Cat>()
{
    orientalCatBreakfast,
    orientalCatLunch,
    orientalCatDinner
};

But if I then want to put these diets into a single list, I get a conversion error:但是,如果我想将这些饮食放入一个列表中,则会出现转换错误:

// This isn't allowed!
List<Diet<Pet>> = new List<Diet<Pet>>()
{
    mediumDogDiet,
    orientalCatDiet
};

I was under the impression that the list would allow Cat and Dog objects because the Pet costraint is more general, but apparently there's something going wrong here.我的印象是该列表将允许CatDog对象,因为Pet costraint 更通用,但显然这里出了点问题。 How can I alter my Pet class or the collection implementation to allow a list that can hold both dog and cat diets (or any other future pet derivative for that matter)?如何更改我的Pet class 或集合实现以允许包含狗和猫饮食(或任何其他未来的宠物衍生品)的列表?

You need co-varience:你需要协方差:

Take note that this means that you have to create a collection of the interface IDiet请注意,这意味着您必须创建接口IDiet的集合

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace ConsoleApp8
{

    public class Pet {  }
    public class Dog : Pet {  }
    public class Cat : Pet { }

    // Meals and diets

    public interface IMeal<out T> : IReadOnlyCollection<T> where T : Pet
    {
    }

    public interface IDiet<out T> : IReadOnlyCollection<IMeal<T>> where T : Pet
    {
    }

    public class Meal<T> : Collection<T>, IMeal<T> where T : Pet
    {
        public List<T> AllowedPets { get; set; } = new List<T>();
    }
    public class Diet<T> : Collection<IMeal<T>>, IDiet<T> where T : Pet
    {
        public List<Meal<T>> DietMeals { get; set; } = new List<Meal<T>>();
    }

    class Program
    {
        static void Main(string[] args)
        {
            Dog labrador = new Dog() { };
            Dog dalmatian = new Dog() { };
            Meal<Dog> mediumDogBreakfast = new Meal<Dog>{ labrador, dalmatian };
            Meal<Dog> mediumDogLunch = new Meal<Dog>{ labrador, dalmatian };
            Meal<Dog> mediumDogDinner = new Meal<Dog>{ labrador, dalmatian };
            Diet<Dog> mediumDogDiet = new Diet<Dog>()
            {
                mediumDogBreakfast,
                mediumDogLunch,
                mediumDogDinner
            };

            // Cats and their diets
            Cat siamese = new Cat() { };
            Cat sphynx = new Cat() { };
            Meal<Cat> orientalCatBreakfast = new Meal<Cat>(){ siamese, sphynx };
            Meal<Cat> orientalCatLunch = new Meal<Cat>(){ siamese, sphynx };
            Meal<Cat> orientalCatDinner = new Meal<Cat>(){ siamese, sphynx };
            Diet<Cat> orientalCatDiet = new Diet<Cat>()
            {
                orientalCatBreakfast,
                orientalCatLunch,
                orientalCatDinner
            };

            List<IDiet<Pet>> diets = new List<IDiet<Pet>>
            {
                mediumDogDiet,
                orientalCatDiet
            };
        }
    }
}

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

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