Определение производных типов из списка объектов базового класса

StackOverflow https://stackoverflow.com/questions/2074779

Вопрос

Это может показаться своего рода "домашним заданием" и / или тривиальным, но это для реальной бизнес-цели;это просто самый простой способ, который я мог придумать, чтобы объяснить, что я концептуально пытаюсь сделать.

Предположим, у меня есть класс Animal и некоторые другие классы (Птица, Кошка, кенгуру).Каждый из них наследуется от Животного.

Животное может выглядеть примерно так:

public class Animal
{
    public Animal()
    {

    }

    public string Name { get; set; }
    public string AnimalType { get; set; }
    public List<Animal> Friends { get; set; }
}

Кенгуру может выглядеть примерно так:

public class Kangaroo : Animal
{
    public Kangaroo()
    {

    }

    public int TailLengthInches { get; set; }
}

Предположим, у кенгуру есть два друга, птица и кошка.Как я мог бы добавить их в список друзей "Animal" (как тип Animal), но сохранить возможность доступа к свойствам производных классов?(например, мне все еще нужно иметь возможность работать со свойствами, специфичными для типа животного, например, с цветом перьев птицы, даже если они будут считаться просто "животными".

Причина, по которой я пытаюсь это сделать, заключается в том, что, когда я позже получу список "друзей" животного, мне жизненно важно знать, к какому типу животных относится этот друг.В зависимости от типа животного (будь то птица, кошка и т.д.) Я хочу сделать что-то другое (на самом деле, показать другой шаблон на странице ASP.NET, но мне не нужна помощь конкретно с этим).

Я предполагаю, что это сводится к следующему ... если у меня есть список Animal , как я могу узнать, какой производный тип был для каждого из объектов в списке, чтобы я мог привести их обратно к их производному типу или сделать что-то еще, что позволит мне получить доступ к конкретным, различным свойствам, которые есть у каждого производного типа?

Спасибо!

Это было полезно?

Решение

Вы можете использовать LINQ для фильтрации по типу, который вы ищете.

animals.Friends = new List<Animal> { new Kangaroo(), new Bird() };
foreach ( var kangaroo in animals.Friends.OfType<Kangaroo>()) {
  kangaroo.Hop();
}

Другие советы

Попробуйте провести кастинг:

var friendBird = friend as Bird;
if (friendBird != null)
{
    // It's a bird, so do something with it
)

Вы можете использовать typeof чтобы получить фактический тип, или используйте is или as операторы для тестирования и, при необходимости, приведения:

foreach (Animal a in Friends)
{
  Kangaroo k = a as Kangaroo;
  if (a != null)
  {
    // it's a kangaroo
    k.JumpAround();
  }
  Ostrich o = a as Ostrich;
  if (o != null)
  {
    o.StickHeadInSand();
  }
}

(я не использовал else здесь предложения, которые могут вызвать ошибки, если вы тестируете типы, которые могут находиться в иерархии, например.если бы у вас были предложения «Кенгуру» и «Сумчатые», вы, вероятно, НЕ хотели бы, чтобы оба выполнялись!)

Вы также можете сделать это с помощью is оператор, который выглядит красивее, но заставит FxCop плакать:

foreach (Animal a in Friends)
{
  if (a is Kangaroo)
  {
    ((Kangaroo)a).JumpAround();
  }
}

А вообще, кстати, вы наверняка захотите поискать возможность поставить виртуальный метод на Animal и реализовать этот метод полиморфно, вместо того, чтобы использовать чудовищные операторы if, которые приводят к хрупкой связи с определенным набором производных классов.

Используйте ключевое слово "is".

если (животное - это Птица) ...

animals.Friends = new List<Animal> { new Kangaroo(), new Bird() };
foreach (Animal animal in animals.Friends)
{
if (animal is Kangaroo)
Console.WriteLine("Kangaroo");
else if (animal is Bird)
Console.WriteLine("Bird");
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top