【问题标题】:How to define a method that takes List<Base> and also List<Derived> in C#如何在 C# 中定义一个采用 List<Base> 和 List<Derived> 的方法
【发布时间】:2018-11-21 16:54:28
【问题描述】:

我有以下方法

List<List<Animal>> animalsList = new List<List<Animal>>();

public void AddAnimal(List<Animal> animals)
{
   animalsList.Add(animals);
}

List&lt;Dog&gt;如何使用这种方法?

我试过了

public void AddAnimal<T>(List<T> animals) where T: Animal
{
   animalsList.Add(animals);
}

这也不起作用。有没有办法定义这样的方法? 我会使用IEnumerable&lt;Animal&gt;,但我需要将.Add().Clear() 和此类方法反映到内部列表中,而无需明确执行。

【问题讨论】:

  • 看起来Animal应该是一个接口。
  • @ozgur 因为那如果Dog实现了接口,你就可以轻松做到animalsList.Add(listOfDogs);
  • 后一个例子加上一个额外的 .Cast 会修复它吗?
  • @Sam 创建一个新列表。然后我失去了对那些内部列表的引用。

标签: c# list generics


【解决方案1】:

您在这里寻找的是协方差,C# 不支持泛型类,但支持泛型接口。此外,IList&lt;T&gt; 不是协变的,但 IEnumerable&lt;T&gt; 是协变的。

您可以更改参数以接收IEnumerable&lt;Animal&gt;,然后强制转换为方法内的列表,这样您就可以将Animal 的派生类型的集合传递给方法。

【讨论】:

  • 如果我使用 IEnumerable 那么我不能强制 api 用户将 List 作为参数。我说的对吗?
  • 您无法在编译时强制执行此操作,但如果它们传入您不想使用的类型,则可以进行类型检查并引发异常。有点脏,但它让你更接近你的意图。
  • @ozgur:如果你查看你的原始代码,你就会明白为什么IList&lt;T&gt; 不能是协变的。如果您使用List&lt;Dog&gt;,您最终可能会在您的狗列表中添加任意动物。之后会发生不好的事情。数组是协变的(由于历史原因可以追溯到通用时代之前),它们的协变是框架中主要的类型安全漏洞。简单集合 (IEnumerable&lt;T&gt;) 可以是协变的,因为它们只能读取,不能更改。
  • @Flydog57 你说得对。我认为,因为你所说的,我想要的似乎并不合理。但是,在少数情况下,能够做到这一点将是无价的。
【解决方案2】:

尝试以下:

        public void AddAnimal<T>(List<T> animals) where T : Animal
        {
            animalsList.Add(animals.Cast<Animal>().ToList());
        }

【讨论】:

    猜你喜欢
    • 2018-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多