15

It seems to me that a lot of the extension methods on IList<T> are just as applicable to IEnumerable<T> - such as FindAll and RemoveAll.

Can anyone explain the reasoning why they are not there?

bluish
  • 26,356
  • 27
  • 122
  • 180
Andy
  • 10,412
  • 13
  • 70
  • 95

5 Answers5

26

RemoveAll makes no sense since there is no Remove etc on that API - however there is a FindAll from 3.5 onwards - but it is known as Where:

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

which is equivalent to:

IEnumerable<Foo> source = ...
var filtered = from x in source
               where x.IsActive && x.Id == 25
               select x;
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • Thanks for the explanation, I see more of the picture now but could I follow up with 2 related questions: (1) why does List implement FindAll as well as Where, assuming they are the same: (2) Why does ICollection not implement RemoveAll since it does implement Remove? Thanks Andy – Andy Mar 19 '12 at 14:48
  • @Andy I don't think there is a reason for it, but you can write a extension method on your own, look at my answer. – Felix K. Mar 19 '12 at 14:55
  • @Andy `List` gets a `Where` because it implements `IEnumerable`. Re `ICollection`: because it is not a good idea to add extra methods to interfaces, HOWEVER, it would be perfectly possible to implement that using an extension method on the interface, – Marc Gravell Mar 19 '12 at 14:55
  • Thanks for those replies. I think the other thing that confused me is that IEnumerable does have a remove method http://msdn.microsoft.com/en-us/library/bb357554.aspx but on closer inspection it does something different – Andy Mar 19 '12 at 15:35
  • @MarcGravell: With regard to `ICollection`, it may not be practical to add methods to an existing interface, but a `RemoveAll` would have been more justifiable as part of a standard collection interface than `Find` or `Remove` [any collection which returns `false` for `IsReadOnly` should be able to implement it, and there's really no way to achieve equivalent functionality without it]. – supercat Jan 07 '14 at 23:42
10

Enumerable does not imply there is an underlying collection, so you can't know whether there is something to remove from or not. If there is an underlying collection, you don't know whether it supports a remove operation.

Here is an example method that enumerates odd numbers. If you could "remove" 7 from enumerable, what would happen? Where would it be removed from?

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

What you might be looking for is Where and Except that allows you to filter the enumerable.

Anders Forsgren
  • 10,827
  • 4
  • 40
  • 77
1

To be fair something like IEnumerable<T>.RemoveAll can actually make sense if what you actually want is a zero length version of a particular collection. Calling it RemoveAll does NOT make sense since no IEnumerable<T> method implementation should modify a collection.

So in my case I sometimes use a custom extension method I call Nil.

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

As for FindAll as Marc already pointed out is simply called Where.

cdiggins
  • 17,602
  • 7
  • 105
  • 102
1

For RemoveAll isn't applicable on IEnumerable because IEnumerable is read-only. For FindAll, see Marc's answer.

Arnaud F.
  • 8,252
  • 11
  • 53
  • 102
1

All IEnumerable does is specify that there is a collection that can be enumerated or iterated over. It does not even specify that the collection can be iterated over multiple times, let alone manipulated. Therefore, any methods that manipulate the collection do not make sense. Methods such as FindAll would make sense, however.

Steven Oxley
  • 6,563
  • 6
  • 43
  • 55