LINQ operations shouldn't have side effects or do actions. They should only be used to produce, from a IEnumerable<T> another IEnumerable<T> (or from a IQueryable<T> another IQueryable<T> or IEnumerable<T>) (or if aggregating, like .Max, .All... a single result)
Read for example http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx.
(and note that this question is quite asked on SO... Read for example my reply here ToList().ForEach in Linq and see a solution to a similar problem)
Now, if you hate yourself enough, you can do this:
strs.Select((p, index) =>
{
Console.WriteLine("#" + index + " " + "<" + p + ">");
return true;
}).All(p => p);
We are using the .All(p => p) to "materialize" the Select operation. This because Select is "lazy" and won't be executed if no one cycles it.
Technically you could even try to obfuscate it a little:
strs.Select((p, index) =>
{
Console.WriteLine("#" + index + " " + "<" + p + ">");
return false;
}).Any(p => p);
(All checks that all the elements are true and stops if one of the is false, so it has to cycle all of them (because we always return true;). Any (as written) checks that at least one of the elements is true and then stops (but all of our elements are false, becasue we do return false; so the Any will cycle all the elements)
Now... The advantage of these techniques over using ToList is that we aren't "duplicating" an Array to a List<T> just to use a "wrong" method of List<T>. If the ForEach method of List<T> is "wrong", duplicating an Array to a List just to use it is doubly-wrong.