c#如何将对象列表传递给构造函数

本文关键字:构造函数 列表 对象 | 更新日期: 2023-09-27 18:16:06

我想传递一个对象列表给NavigationPage的构造函数,这样我就可以在那个页面上填充ListView的内容。

对象将是不同类型的,都继承自同一个父类,父类是一个抽象类,称为"Animal",定义如下:

abstract class Animal { ...

继承的类是这样的:

public class Horse : Animal { ...
public class Cow : Animal { ...
public class Dog : Animal { ...

显示此列表的页面是继承自NavigationPage的类,如下所示:

public List<Animal> Animals = new List<Animal>();
    public AnimalListPage(string title, List<Animal> animals) {
    ....

和我创建的AnimalListPage对象如下:

var horses = new List<Horse>() {
    new Horse("Silver", 65, 70),
    new Horse("Tucker", 60, 68)
};
horsesListPage = new AnimalListPage("Horses", horses);
....

编辑:回应一些建议;澄清一下:我需要在列表中保留"马"、"牛"、"狗"等对象类型,因为每种动物类型都有要显示的唯一属性。此外,Animal List的每个实例只能有一种类型,即永远不会有马、牛和狗的组合列表。

但是我得到错误:

Error CS1503 Argument 2: cannot convert from System.Collections.Generic.List<AnimalTracker.Horse> to System.Collections.Generic.List<AnimalTracker.Animal>

我是否需要在"马"列表中输入"动物"?或者使"AnimalListPage()"构造函数不那么特定于类型?我怎么做呢?

注意:我正在使用Xamarin进行开发(尽管我认为这与此问题无关)。

c#如何将对象列表传递给构造函数

按照构造函数的要求将列表设置为List<Animal>:

var horses = new List<Animal>() {
    new Horse("Silver", 65, 70),
    new Horse("Tucker", 60, 68)
};

如果您不控制值的来源,并且它可以是任何派生类型的List<T>,则需要执行强制转换操作以将其用作List<Animal>:

var horses = someExistingList.Cast<Animal>().ToList();

让我稍微解释一下这种情况的本质。
不能隐式地将集合转换为基类型的集合,即使它听起来安全且正确。
想象下面的情况:

public void CalledMethod(List<Animal> animals)
{ 
    animals.Add(new Dog()); 
    // error! you've tried to insert a dog into List<Horse>
}
public void CallingMethod()
{
    var horses = new List<Horse>() {
      new Horse("Silver", 65, 70),
      new Horse("Tucker", 60, 68)
    };
    CalledMethod(horses);
    string result = horses[2].RideOrDoSomeOtherHorseOnlyThings(); // it would be strange
}

您需要通过声明List<Animal>而不是List<Horse>来传递Animal的集合,或者使用.Cast<Animal>()扩展方法,正如其他回答者已经完全描述的那样。

以下是一些选项:

简单的解决方案是使用List<Animal>而不是List<Horse>。然后你的代码将符合构造函数所要求的类型。

更复杂的是使AnimalListPage通用。然后,您可以强类型地键入想要在AnimalListPage中使用的Animal类型。这将只工作,如果你有一个单一类型的Animal你想使用。

最后一个选项是使用协变接口IAnimal,并将其用作列表类型。所有Animal类型都应该实现这一点,但我想你可以在你的基类中实现这一点。或者使用协变集合接口,如IEnumerable<Animal>