【问题标题】:C# how to pass a list of objects to a constructor?C#如何将对象列表传递给构造函数?
【发布时间】:2017-03-17 07:53:36
【问题描述】:

我想将对象列表传递给 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 的每个实例都只会有一种类型,即永远不会有一个组合了 Horses、Cows 和 Dogs 的列表。

但我得到了错误:

Error CS1503 Argument 2: cannot convert from System.Collections.Generic.List&lt;AnimalTracker.Horse&gt; to System.Collections.Generic.List&lt;AnimalTracker.Animal&gt;

我是否必须“投射”“马”列表才能以某种方式键入“动物”?或者使“AnimalListPage()”构造函数的类型不那么具体?我该怎么做?

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

【问题讨论】:

  • var horses = new List() {...
  • 只要使用var horses = new List&lt;Animal&gt;()

标签: c# list types constructor


【解决方案1】:

只需按照构造函数的预期将您的列表设为List&lt;Animal&gt;

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

如果您不控制值的来源并且它可以是任何派生类型的List&lt;T&gt;,您可能需要执行转换操作以将其用作List&lt;Animal&gt;

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

【讨论】:

    【解决方案2】:

    这里有一些选项:

    简单的解决方案是使用List&lt;Animal&gt; 而不是List&lt;Horse&gt;。那么你的代码就会符合构造函数请求的类型。

    更复杂的是使AnimalListPage 通用。然后您可以在AnimalListPage 中强输入您想要使用的Animal 类型。这仅在您想要使用一种单一类型的 Animal 时才有效。

    最后一个选项是使用协变接口IAnimal,并将其用作列表类型。所有Animal 类型都应该实现它,但我想你已经可以在你的基类中实现它了。或者使用协变集合接口,例如IEnumerable&lt;Animal&gt;

    【讨论】:

    • 错过了一个选项(有点,你的最后一个选项谈到了它)。如果可能,将构造函数更改为采用IReadOnlyList&lt;Animial&gt;IReadOnlyCollection&lt;Animal&gt;IEnumerable&lt;Animal&gt;(所有协变接口)。无需创建IAnimal
    • 我编辑了问题以澄清我需要保留对象类型。考虑到这一点,我想要的第二个选项“使AnimalListPage”更通用。但是怎么做呢?
    【解决方案3】:

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

    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&lt;Animal&gt; 而不是List&lt;Horse&gt; 或使用.Cast&lt;Animal&gt;() 扩展方法来传递Animal 的集合,正如其他回答者已经充分描述的那样。

    【讨论】:

      猜你喜欢
      • 2018-08-04
      • 2014-06-04
      • 2010-11-17
      • 1970-01-01
      • 2020-07-22
      • 2019-08-07
      • 2016-02-15
      • 1970-01-01
      • 2021-06-30
      相关资源
      最近更新 更多