带接口的C#泛型

use*_*000 5 c# generics

我正在尝试学习如何使用c#创建泛型类.有人可以解释为什么我运行这个程序时出现编译错误.

我创建了IZooAnimal接口.所有动物园动物都将实现此界面.

public interface IZooAnimal
{
    string Id { get; set; }
}

public class Lion : IZooAnimal
{
    string Id { get; set; }
}

public class Zebra : IZooAnimal
{
    public string Id { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

ZooCage将容纳相同类型的动物

public class ZooCage<T> where T : IZooAnimal
{
    public IList<T> Animals { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

动物园类有笼子

public class Zoo
{
    public IList<ZooCage<IZooAnimal>> ZooCages { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

使用类的程序

class Program
{
    static void Main(string[] args)
    {
        var lion = new Lion();
        var lionCage = new ZooCage<Lion>();
        lionCage.Animals = new List<Lion>();
        lionCage.Animals.Add(lion);

        var zebra = new Zebra();
        var zebraCage = new ZooCage<Zebra>();
        zebraCage.Animals = new List<Zebra>();
        zebraCage.Animals.Add(zebra);

        var zoo = new Zoo();
        zoo.ZooCages = new List<ZooCage<IZooAnimal>>();

       zoo.ZooCages.Add(lionCage);
    }
}
Run Code Online (Sandbox Code Playgroud)

当我编译时,我得到以下错误:错误2参数1:无法从' ConsoleApplication2.ZooCage<ConsoleApplication2.Lion>' 转换为' ConsoleApplication2.ZooCage<ConsoleApplication2.IZooAnimal>'

为了让程序运行,我需要做哪些更改?

pas*_*sty 2

您不应该使用实现接口的具体类型来定义列表,而是使用接口来定义列表:

    var lionCage = new ZooCage<IZooAnimal>();
    lionCage.Animals = new List<IZooAnimal>();
Run Code Online (Sandbox Code Playgroud)

然后您的代码将按预期工作。

初始代码不起作用,因为不允许将具体类型转换为通用类型(正如 @default.kramer 指出的协变和逆变)。

我提出的解决方案如下:

// your ZooCage is still generic
public class ZooCage<T>
{   
    // but you declare on creation which type you want to contain only!
    private Type cageType = null;
    public ZooCage(Type iMayContain)
    {
        cageType = iMayContain;
        animals = new List<T>();
    }
    // check on add if the types are compatible
    public void Add(T animal)
    {
        if (animal.GetType() != cageType)
        {
            throw new Exception("Sorry - no matching types! I may contain only " + cageType.ToString());
        }
        animals.Add(animal);
    }
    // should be generic but not visible to outher world!
    private IList<T> animals { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

此代码允许您执行以下操作:

    var lion = new Lion();
    var lionCage = new ZooCage<IZooAnimal>(typeof(Lion));
    lionCage.Add(lion);

    var zebra = new Zebra();
    var zebraCage = new ZooCage<IZooAnimal>(typeof(Zebra));
    zebraCage.Add(zebra);
Run Code Online (Sandbox Code Playgroud)

但它会抛出错误:

    zebraCage.Add(lion);
Run Code Online (Sandbox Code Playgroud)

现在动物园可以安全地扩建了。

  • 这将防止编译错误,但它违背了使用泛型的全部目的。如果您打算这样做,最好不要使 ZooCage 通用。它也不满足“动物园笼子将容纳相同类型的动物”的要求,因为所有笼子都将容纳任何类型的动物。 (2认同)