Понижение списка объектов в C # - PullRequest
9 голосов
/ 08 марта 2011

Как можно уменьшить список объектов так, чтобы каждый из объектов в списке был понижен до объекта производного класса?

Это сценарий.

У меня естьбазовый класс с List базовых элементов и двумя унаследованными от него классами:

public class BaseClass
{
    public List<BaseItem> items;
    protected BaseClass()
    {
        // some code to build list of items
    }
}
public class DerivedClass : BaseClass
{
    public DerivedClass : base() {}
}
public class AnotherDerivedClass : BaseClass
{
    public AnotherDerivedClass : base() {}
}

public class BaseItem {}
public class DerivedItem : BaseItem {}
public class AnotherDerivedItem : BaseItem {}

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

Проблема возникает, когда у меня есть список их.List из BaseItem объявлено в BaseClass, потому что оно должно быть у всех производных классов.Но при доступе к нему во время выполнения я, похоже, не могу опуститься до производного класса.

Ответы [ 4 ]

7 голосов
/ 08 марта 2011

Использование LINQ:

    var baseList = new List<BaseClass>();
    var derivedList = baseList.Cast<DerivedClass>();

Примечание: необходимость понижения обычно является «запахом» и указывает на то, что иерархия наследования неверна или неправильно реализована.Идея наличия базового класса состоит в том, что вы можете рассматривать все подклассы как суперклассы без необходимости понижать их до отдельных типов подклассов.

Вместо Cast вы можете использовать OfType, чтобы "выловить" определенныепроизводные классы из коллекции суперклассов.Но опять же, в этом не должно быть необходимости.

Спросите себя, зачем вам нужен подкласс - может быть, вам нужно перенести некоторые функции в базовый класс?

6 голосов
/ 08 марта 2011

Я верю, что вы хотите использовать дженерики:

public class BaseClass<T> where T: BaseItem, new()
{
    public List<T> items;
    protected BaseClass()
    {
        items = new List<T>();
        T item = new T();
        item.SomePropertyOfBaseItem=something;
        items.Add(item);
    }
}

public class DerivedClass: BaseClass<DerivedItem>

Это приведет к тому, что items in DerivedClass будет List<DerivedItem>. where обеспечивает использование только типов, производных от BaseItem.

edit : "downcasting", приведение типа к производному типу, на самом деле не то, что вы пытаетесь сделать здесь. Ваше намерение состоит в том, чтобы объекты производного списка использовали определенный тип производного элемента в соответствии с дизайном, и, вероятно, вы хотите хранить экземпляры объектов производного типа в вашем классе производного списка.

Таким образом, это может работать просто отлично без использования шаблонов: List<BaseItem> прекрасно способен хранить любые элементы, которые происходят от BaseItem. Однако вам нужно будет ссылаться на эти объекты из списка, используя приведение (как описано в других ответах), чтобы получить доступ к производным свойствам. Но это просто «приведение» объекта к его истинному типу. Обобщения дают вам возможность предоставить строго типизированный доступ к этим объектам напрямую.

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

0 голосов
/ 23 сентября 2015

Вы также можете использовать LINQ для итерации по элементам базового класса и понижения каждого элемента, например:

var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.ForEach(v => derivedList.Add((DerivedClass)v));

Если вам необходимо проверить производный тип каждого элемента перед приведением:

var baseList = new List<BaseClass>();
var derivedList = new List<DerivedClass>();
baseList.OfType<DerivedClass>().ToList().ForEach(v => derivedList.Add(v));

Для получения дополнительной информации ознакомьтесь со следующими статьями:

0 голосов
/ 08 марта 2011
public class Zoo
{
     public List<Animal> items;
     protected BaseClass()
     {         // some code to build list of items     }
 }

public class PettingZoo : Zoo
{
     public PettingZoo : base() {}
}

public class CatComplex : Zoo
{
     public CatComplex : base() {}
}

public class Animal {}
public class Sheep : Animal {}
public class Tiger : Animal {}

...

PettingZoo myZoo = new PettingZoo();
myZoo.items.Add(new Tiger());

PettingZoo не взаимозаменяем с Zoo, так как PettingZoo должен ограничивать типы животных. Таким образом, этот проект не соответствует принципу подстановки Лискова .

...