When i use a standard Extension Method on a List such as Where(...)
the result is always IEnumerable, and when you decide to do a list operation such as Foreach()
we need to Cast(not pretty) or use a ToList() extension method that
(maybe) uses a new List that consumes more memory (is that right?):
List<string> myList=new List<string>(){//some data};
(Edit: this cast on't Work)
myList.Where(p=>p.Length>5).Tolist().Foreach(...);
or
(myList.Where(p=>p.Length>5) as List<string>).Foreach(...);
Which is better code or is there a third way?
Edit: Foreach is a sample, Replace that with BinarySerach
myList.Where(p=>p.Length>5).Tolist().Binarysearch(...)
The
as
is definitely not a good approach, and I'd be surprised if it works.In terms of what is "best", I would propose
foreach
instead ofForEach
:If you desperately want to use list methods, perhaps:
or indeed
but note that this does (unlike the first) require an additional copy of the data, which could be a pain if there are 100,000 items in
myList
with length above 5.The reason that LINQ returns
IEnumerable<T>
is that this (LINQ-to-Objects) is designed to be composable and streaming, which is not possible if you go to a list. For example, a combination of a fewwhere
/select
etc should not strictly need to create lots of intermediate lists (and indeed, LINQ doesn't).This is even more important when you consider that not all sequences are bounded; there are infinite sequences, for example:
as until the
ToList
it is composing iterators, not generating an intermediate list. There are a few buffered operations, though, likeOrderBy
, which need to read all the data first. Most LINQ operations are streaming.If you want to make a simple foreach over a list, you can do like this:
One of the design goals for LINQ is to allow composable queries on any supported data type, which is achieved by having return-types specified using generic interfaces rather than concrete classes (such as
IEnumerable<T>
as you noted). This allows the nuts and bolts to be implemented as needed, either as a concrete class (e.g.WhereEnumerableIterator<T>
or hoisted into a SQL query) or using the convenientyield
keyword.Additionally, another design philosophy of LINQ is one of deferred execution. Basically, until you actually use the query, no real work has been done. This allows potentially expensive (or infinite as Mark notes) operations to be completed only exactly as needed.
If
List<T>.Where
returned anotherList<T>
it would potentially limit composition and would certainly hinder deferred execution (not to mention generate excess memory).So, looking back at your example, the best way to use the result of the
Where
operator depends on what you want to do with it!You can't cast (
as
)IEnumerable<string>
toList<string>
.IEnumerable
evaluates items when you access those. InvokingToList<string>()
will enumerate all items in the collection and returns a new List, which is a bit of memory inefficiency and as well as unnecessary. If you are willing to useForEach
extension method to any collection its better to write a newForEach
extension method that will work on any collection.