Почему IEnumerable <T> не имеет методов FindAll или RemoveAll?

Мне кажется, что многие методы расширения на IList<T> применимы к IEnumerable<T> - например, FindAll и RemoveAll.

Может ли кто-нибудь объяснить, почему их там нет?

Ответ 1

RemoveAll не имеет смысла, поскольку в этом API нет Remove и т.д., однако есть a FindAll с 3,5 года, но он известен как Where:

IEnumerable<Foo> source = ...
var filtered = source.Where(x => x.IsActive && x.Id = 25);

что эквивалентно:

IEnumerable<Foo> source = ...
var filtered = from x in source
               where x.IsActive && x.Id == 25
               select x;

Ответ 2

Enumerable не означает, что существует базовая коллекция, поэтому вы не можете знать, есть ли что-то, что нужно удалить или нет. Если существует базовая коллекция, вы не знаете, поддерживает ли она операцию удаления.

Вот пример метода, который перечисляет нечетные числа. Если бы вы могли "удалить" 7 из перечислимого, что произойдет? Где он будет удален из?

public IEnumerable<int> GetOddPositiveNumbers()
{
   int i = 0;
   while (true)
   {          
      yield return 2*(i++)+1;
   }
}

То, что вы, возможно, ищете, - это Where и Except, что позволяет фильтровать перечисляемые.

Ответ 3

Для RemoveAll не применимо к IEnumerable, потому что IEnumerable доступен только для чтения. Для FindAll см. Ответ Marc.

Ответ 4

Все IEnumerable указывает, что существует коллекция, которая может быть перечислина или переименована. Он даже не указывает, что сбор может быть повторен многократно, не говоря уже о манипулировании. Поэтому любые методы, управляющие коллекцией, не имеют смысла. Однако методы, такие как FindAll, имеют смысл.

Ответ 5

Чтобы быть справедливым, что-то вроде IEnumerable<T>.RemoveAll может иметь смысл, если то, что вы на самом деле хотите, это версия нулевой длины конкретной коллекции. Вызов RemoveAll не имеет смысла, поскольку реализация метода IEnumerable<T> должна изменять коллекцию.

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

static IEnumerable<T> Nil<T>(this IEnumerable<T> self) {
  yield break;
} 

Что касается FindAll, как уже указывал Марк, просто называется Where.