Запрос Linq и листинг в С#

61
6

У меня есть класс под названием BaseViewModel и несколько классов, наследующих его.

У меня есть List<BaseViewModel> который содержит все дочерние классы, а не один BaseViewModel.

Теперь я хотел бы извлечь все классы определенного типа, например DateViewModel, из List<BaseViewModel>

Сейчас я делаю это, что вызывает InvalidCastException:

CustomFieldViewModels - это мой List<BaseViewModel> который содержит перечисление ControlType которое я использую для распознавания всех "дочерних".

public List<DateViewModel> DateCustomViewModels
{
get
{
return (List<DateViewModel>)CustomFieldViewModels
.Where(x => x.ControlType == CustomFieldControlValueType.Date);
}
}

Я довольно незнакома с Linq, и я не уверен, что я делаю неправильно.

Я также уверен, что выполнение foreach и заполнение List<DateViewModel> не так хорошо работает и не очень чистое.

Из того, что я понимаю, .Where вернет List того, что я спросил, с фильтром (здесь, мой перечисление). Я не понимаю, почему возникает проблема с тем, что все мои дочерние объекты наследуются от родительского класса, и я не использую дочерний элемент в моей фильтрации. Кроме того, даже если тип основного списка имеет Base, ни один из его элементов не имеет базового типа, поэтому в первую очередь не должно выполняться кастинг.

Я чувствую, что мне не хватает чего-то ужасно очевидного, но я не вижу его, любая помощь приветствуется.

Если вы дадите ответ, было бы очень признательно, если бы вы могли дать небольшое объяснение, а не только код для копирования-вставки :)

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

public IEnumerable<DateControlViewModel> DateCustomViewModels
{
get
{
return CustomFieldControlViewModels.OfType<DateControlViewModel>();
}
}

спросил(а) 2015-11-05T13:58:00+03:00 4 года, 3 месяца назад
1
Решение
78

Вам нужно использовать OfType():

public List<DateViewModel> DateCustomViewModels
{
get
{
return CustomFieldViewModels.OfType<DateViewModel>().ToList()
}
}

Из того, что я понимаю,.Where вернет список того, что я спросил, с фильтром (здесь, моим перечислением)

Нет, он вернет IEnumerable<BaseViewModel>. Критерии, которые вы указали в Where(), не меняют тип возвращаемого значения, он указывает только, какие из объектов BaseViewModel будут включены.

Я не понимаю, почему возникает проблема с тем, что все мои дочерние объекты наследуются от родительского класса, и я не использую дочерний элемент в моей фильтрации.

Несмотря на то, что DateViewModel наследуется от BaseViewModel, вы не можете явно List<DateViewModel> из List<DateViewModel> в List<BaseViewModel> потому что List<T> является инвариантным.

Кроме того, даже если тип основного списка имеет Base, ни один из его элементов не имеет базового типа, поэтому в первую очередь не должно выполняться кастинг.

Вы правы, нет необходимости в кастинге. Используйте OfType<DateViewModel>() который будет возвращать только объекты, которые являются DateViewModel. Кроме того, возвращаемый набор теперь является IEnumerable<DateViewModel> (он больше не является List<BaseViewModel>), и компилятор может проверить, что он совместим с возвращаемым типом свойства DateCustomViewModels.

См. MSDN

ответил(а) 2015-11-05T14:01:00+03:00 4 года, 3 месяца назад
49

Из других ответов теперь должно быть ясно, что нет способа List<DateViewModel> результат запроса в List<DateViewModel>. Что может быть неясно, так это то, что решения включают создание нового списка. Наличие свойства списка типов, которое создает новый список в любое время, называется ужасной идеей. Рассмотрим следующие случаи

// user of your class
yourClass.DateCustomViewModels.Add(new DateViewModel()); // goes nowhere
yourClass.DateCustomViewModels.RemoveAt(0); // removes nothing
// or trying to be smart
for (int i = 0; i < yourClass.DateCustomViewModels.Cout; i++
{
var model = yourClass.DateCustomViewModels[i];
}
// etc.

То, что вы действительно должны сделать, это изменить вашу подпись

public IEnumerable<DateViewModel> DateCustomViewModels
{
get
{
// use some of the suggestions in other answers
// with ToList call removed
}
}

ответил(а) 2015-11-05T14:32:00+03:00 4 года, 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема