【问题标题】:Method that excepts objects of derived class [duplicate]排除派生类对象的方法[重复]
【发布时间】:2015-04-26 06:54:42
【问题描述】:

在下面的示例中,我可以添加 List 类型为 Animal。由于DogCat 派生自动物,因此List 可以分别保存。但是,如果我有一个接受List<Animal> 的方法,则不能传入引用List<Dog>。如果Dog 来源于动物,为什么这无效?但是,如果我有一个方法可以排除 Object 类型的参数,并且所有对象都派生自 Object,那么它可以工作。

class Program
{
    static void Main(string[] args)
    {
       List<Animal> animals = new List<Animal>();
       animals.Add(new Dog() { Color = "Black" }); // allowed since Dog derives from Animal

       List<Dog> dogs = new List<Dog>();
       dogs.Add(new Dog() { Color = "White" });

       Test(animals);
       Test(dogs); // not allowed - does not compile
       Test2(dogs); // valid as all objects derive from object
    }

    static void Test(List<Animal> animals) {
        // do something
    }

    static void Test2(object obj) { 

    }
}

public class Animal {

   public String Color { get; set; }

}

public class Dog : Animal { }
public class Cat : Animal { }

【问题讨论】:

  • 试试static void Test(IEnumerable&lt;Animal&gt; animals)
  • 搜索covariance and contravariance in c#
  • 正如 Selman22 建议的那样,看看here
  • @MatthewWatson - 听起来像是答案。为什么不让它成为一个答案?
  • @PhilVallone 已添加到我现有的答案中。

标签: c#


【解决方案1】:

想象一下Test(dogs) 确实编译了。然后想象Test()的实现如下:

static void Test(List<Animal> animals)
{
    animals.Add(new Cat()); // Where Cat is derived from Animal
}

您刚刚在狗列表中添加了一只猫……显然这是不允许的。这就是为什么它不是。

但是,如果您只是访问列表的元素而不是添加到列表中,您可以像这样声明Test()

static void Test(IEnumerable<Animal> animals)
{
    foreach (var animal in animals)
    {
        // Do something with animal.
    }
}

然后您可以传递任何实现IEnumerable&lt;T&gt; 的集合类型,例如List&lt;T&gt; 和普通数组。

【讨论】:

  • 这很有意义。
  • 嗯,给狗加猫通常很有趣,所以我允许... ;)
  • 狗和猫...在同一个List&lt;Animal&gt;...Mass Hysteria!!!
  • 取决于用法:IReadOnlyCollection 是协变的。您应该能够将其作为参数传递。它 - 知道 - 你不会添加项目。
  • @Caramiriel 是的,但在这种情况下,最好使用IEnumerable&lt;T&gt;,它适用于更多集合类型。 (请注意,如果您使用的是 .Net 4 或更早版本,则不能使用 IReadOnlyCollection。)
【解决方案2】:

致电Test(dogs.Cast&lt;Animal&gt;().ToList())。将参数类型更改为 IEnumerable 以跳过创建副本的 ToList()

int 是一个objectList&lt;Animal&gt;objectList&lt;Dog&gt; 也是。但是List&lt;Dog&gt; 不是List&lt;Animal&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多