С# приведение объекта к списку базового класса

У меня есть следующая структура класса:

public class Fruit { }
public class Apple : Fruit { }

Затем я использую метод из .net framework, который получает значение свойства из класса, возвращаемого как объект. Так,

// values will be of type List<Apple>
object values = someObject.GetValue()

Теперь у меня есть этот объект значений типа List, и я хочу преобразовать его в список типа Fruit. Я пробовал следующее, но это не сработало.

List<Fruit> fruits = values as List<Fruit>;

Кто-нибудь знает, как привести объект к списку его базового класса?

Обновление: в момент приведения я не знаю, что объект значений имеет тип List. Я просто знаю, что это должен быть список типа, который наследуется от Fruit.


person Nick Olsen    schedule 11.11.2011    source источник


Ответы (3)


Проблема в том, что List<Apple> и List<Fruit> не ковариантны. Сначала вам нужно выполнить приведение к List<Apple>, а затем использовать метод Cast LINQ для приведения элементов к Fruit:

List<Fruit> fruits = values is List<Apple> ? 
    (values as List<Apple>).Cast<Fruit>().ToList() :
    new List<Fruit>();

Если вы не знаете тип заранее и вам не нужно изменять список (и вы используете С# 4.0), вы можете попробовать:

IEnumerable<Fruit> fruits = values as IEnumerable<Fruit>;

Или, я думаю, если вам нужен список:

List<Fruit> fruits = (values as IEnumerable<Fruit>).ToList();
person Justin Niessner    schedule 11.11.2011
comment
Я не знаю, что объект значений имеет тип Apple. Я просто знаю, что он должен относиться к типу, наследующему базовый класс Fruit. - person Nick Olsen; 11.11.2011
comment
@Nick Olsen — обновлены параметры, если вы используете C# 4.0. - person Justin Niessner; 11.11.2011
comment
Я использую С# 4.0 и привожу его к IEnumerable! Есть ли причина, по которой это так и что ее нельзя перевести в List‹Fruit›? - person Nick Olsen; 11.11.2011
comment
@Ник Олсен - Долгая история. Начните читать с первой части по одиннадцатую: блоги .msdn.com/b/ericlippert/archive/tags/ - person Justin Niessner; 11.11.2011
comment
нашел способ сделать это, если вы переходите к методу. Создайте общий метод. .net 4. void метод‹T›(список‹T› список), где T:BaseClass{ }. таким образом вы можете передать метод (список), где список является базовым классом; - person TatiOverflow; 28.09.2019

вам следует попробовать метод linq cast. метод Cast вернет IEnumerable типа, к которому вы применяете...

   List<Fruit> fruits = null;
   if ( values is List<Apples> ) 
     fruits = ((List<Apples>)values).Cast< fruits >.ToList();
person Muad'Dib    schedule 11.11.2011
comment
Но значения имеют тип объекта, и я почти уверен, что метод расширения Cast предназначен только для типов IEnumerable. - person Nick Olsen; 11.11.2011
comment
Это не будет работать без предварительного приведения значений к соответствующему типу (это объект... который не реализует IEnumerable‹T›). - person Justin Niessner; 11.11.2011

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

List<Fruit> fruits = ((IEnumerable)values).Cast<Fruit>().ToList();

Если вы используете .NET 4 (за исключением Silverlight 4), вы можете использовать решение Джастина Нисснера:

List<Fruit> fruits = ((IEnumerable<Fruit>)values).ToList();

Наконец, можно было бы использовать общее решение, если есть сайт вызова, на котором известен статический тип фрукта (Apple или что-то еще). Это означало бы немного изменить код, чтобы вы больше не получали значения с использованием отражения.

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

person phoog    schedule 11.11.2011
comment
спасибо, это единственное, что мне помогло. - person Diogo Neves; 23.05.2018