Фильтрация коллекций из свойства с помощью коллекций Linq

У меня есть объект под названием MyConnection со свойством Sources, который имеет тип List. У меня возникают проблемы с написанием кода linq, чтобы найти все MyConnections в списке, где соединение имеет источник "".

Я пробовал это, но, похоже, он не работает.

MyConnection initialActivity = currentActivities.ToList().Where(x => x.Sources.Contains(String.Empty));

person Nick LaMarca    schedule 13.12.2012    source источник


Ответы (3)


Where возвращает IEnumerable<MyConnection>, а не один MyConnection. Таким образом, вы можете перечислить все в foreach или взять один f.e. с First.

IEnumerable<MyConnection> allWithEmptySource = currentActivities
    .Where(con => con.Sources.Any(s => string.IsNullOrEmpty(s)));
if(allWithEmptySource.Any())
{
    MyConnection first = allWithEmptySource.First();
}
person Tim Schmelter    schedule 13.12.2012
comment
Any на самом деле не является решением здесь, если предположить, что источник действительно "", а не null; Contains лучше использовать для проверки на равенство, так как он может сократить путь к ICollection. - person Rawling; 13.12.2012
comment
@Роулинг: Почему Any неправильно? Он хочет найти все MyConnections в списке, где соединение имеет источник String.Empty. Таким образом, в соединении может быть несколько источников. Но если какой-либо из них пуст, он хочет это MyConnection. - person Tim Schmelter; 13.12.2012
comment
Таким образом, проблема не в том, что он использует Contains, а не Any, а в том, что он пытается сохранить результат в одном элементе, а не в IEnumerable. Any работает в данном случае, но это не то, что не так с исходным кодом, и потенциально это шаг назад по сравнению с Contains. - person Rawling; 13.12.2012
comment
@Роулинг: ты прав. Основная проблема заключается в том, что он не может присвоить IEnumerable<MyConection> одному объекту. Отредактировал мой ответ соответственно. - person Tim Schmelter; 13.12.2012

.Where() возвращает последовательность совпадающих элементов.

Вы не можете присвоить это переменной типа MyConnection.

Вместо этого вы можете вызывать такие методы, как .Last(), чтобы получить один элемент.

person SLaks    schedule 13.12.2012

Если вы пытаетесь получить только одно действие с источником "", а не все, используйте

MyConnection initialActivity = currentActivities.ToList()
    .FirstOrDefault(x => x.Sources.Contains(String.Empty));

что даст вам null, если таких действий нет, и только первое, если есть одно или несколько.

В качестве альтернативы FirstOrDefault используйте:

  • First, чтобы дать вам первое, но бросить исключение, если их нет
  • Single, чтобы дать вам одно совпадение и бросок исключение из 0 или > 1 совпадений
  • SingleOrDefault, чтобы дать вам одно совпадение или нет match, andthrow и exception, если совпадений больше 1.

Если вам нужны все из них, возвращаемый тип будет IEnumerable<MyConnection>, а не один:

IEnumerable<MyConnection> initialActivities = = currentActivities.ToList()
    .Where(x => x.Sources.Contains(String.Empty));

Затем вы можете использовать foreach для этого или вызвать ToList или ToArray для получения списка или массива.

Н.Б. Вероятно, вам не нужно вызывать .ToList() в середине вашей строки здесь.

person Rawling    schedule 13.12.2012