我正在尝试学习如何使用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; }
}
ZooCage将容纳相同类型的动物
public class ZooCage<T> where T : IZooAnimal
{
public IList<T> Animals { get; set; }
}
动物园类有笼子
public class Zoo
{
public IList<ZooCage<IZooAnimal>> ZooCages { get; set; }
}
使用类
的程序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);
}
}
编译时出现以下错误:
错误2参数1:无法从“ConsoleApplication2.ZooCage<ConsoleApplication2.Lion>
”转换为“ConsoleApplication2.ZooCage<ConsoleApplication2.IZooAnimal>
”
为了让我的程序运行,我需要做哪些更改?
答案 0 :(得分:3)
您应该使用实现接口的具体类型定义列表,但使用接口:
var lionCage = new ZooCage<IZooAnimal>();
lionCage.Animals = new List<IZooAnimal>();
然后您的代码将按预期工作。
初始代码不起作用,因为不允许将具体类型转换为通用类型(如@ default.kramer指出covariance and contravariance)。
我提出的解决方案如下:
// 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; }
}
此代码允许您执行以下操作:
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);
但它会引发错误:
zebraCage.Add(lion);
现在动物园可以安全延长。
答案 1 :(得分:3)
@DanielMann的答案非常好,但有一个缺点:原始IList
接口不能与ICage
接口一起使用。相反,ICage必须公开ReadOnlyCollection,并公开一个名为CageAnimal的新方法。
我也用类似的方法重写了代码。我的ICage
实现要弱得多,但它允许你坚持使用IList
语义。
public interface IZooAnimal
{
string Id { get; set; }
}
public class Lion : IZooAnimal
{
public string Id { get; set; }
}
public class Zebra : IZooAnimal
{
public string Id { get; set; }
}
public interface ICage
{
IEnumerable<IZooAnimal> WeaklyTypedAnimals { get; }
}
public class Cage<T> : ICage where T : IZooAnimal
{
public IList<T> Animals { get; set; }
public IEnumerable<IZooAnimal> WeaklyTypedAnimals
{
get { return (IEnumerable<IZooAnimal>) Animals; }
}
}
public class Zoo
{
public IList<ICage> ZooCages { get; set; }
}
class Program
{
static void Main(string[] args)
{
var lion = new Lion();
var lionCage = new Cage<Lion>();
lionCage.Animals = new List<Lion>();
lionCage.Animals.Add(lion);
var zebra = new Zebra();
var zebraCage = new Cage<Zebra>();
zebraCage.Animals = new List<Zebra>();
zebraCage.Animals.Add(zebra);
var zoo = new Zoo();
zoo.ZooCages = new List<ICage>();
zoo.ZooCages.Add(lionCage);
}
}
答案 2 :(得分:2)
由于你想拥有多个笼子,但是每种类型的笼子只能容纳一只动物,你的模型稍微偏离。
我重写了以下代码:
IZooAnimal
没有变化。 ICage
,它接受任何类型的IZooAnimal
。这允许您为每种类型的动物都有一个强类型的笼子。 Cage
ICage
的具体实现。 Cage
是通用的,但您可以轻松地将其作为抽象类,然后进行特定于动物的笼实现。例如,如果您的斑马需要喂草,而您的狮子需要喂肉,您可以专门设置它们的笼子。这是完整的代码:
public interface IZooAnimal
{
string Id { get; set; }
}
public interface ICage<out T> where T : IZooAnimal
{
IReadOnlyCollection<T> Animals { get; }
}
public class Cage<T> : ICage<T> where T: IZooAnimal
{
private readonly List<T> animals = new List<T>();
public IReadOnlyCollection<T> Animals
{
get
{
return animals.AsReadOnly();
}
}
public void CageAnimal(T animal)
{
animals.Add(animal);
}
}
public class Lion : IZooAnimal
{
public string Id { get; set; }
}
public class Zebra : IZooAnimal
{
public string Id { get; set; }
}
public class Zoo
{
public IList<ICage<IZooAnimal>> Cages { get; set; }
}
internal class Program
{
private static void Main(string[] args)
{
var lion = new Lion();
var zebra = new Zebra();
var lionCage = new Cage<Lion>();
lionCage.CageAnimal(lion);
var zebraCage = new Cage<Zebra>();
zebraCage.CageAnimal(zebra);
var zoo = new Zoo();
zoo.Cages.Add(lionCage);
zoo.Cages.Add(zebraCage);
}
}