From the below 2 ways to enumerate a collection, should one be pre开发者_如何学Goferred over the other OR are both the same in terms of performance (i.e. since ToList() conversion is involved in the second approach)
foreach(SomeType st in Collection)
{
//Do something
}
Collection.OfType<SomeType>.ToList().ForEach()
Is there any other way (except using relection)?
EDIT
How about this scenario?
class SomeType : IMyType
{
}
class OtherType : IMyType
{
}
class SomeCollection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable
{
}
Considering MyTypes is a property in a class with type SomeCollection<IMyType>
the below 2 approaches same?
foreach(IMyType mt in MyTypes)
{
if(IMyType is SomeType)
return;
}
OR
if(MyTypes.OfType<SomeType>.Any())
return;
Sure, with indexable collections you could use a classic for loop:
for( int i = 0; i < collection.Count; i++ )
{
collection[i] ... // do something with the item
}
You could also directly access the IEnumerator
object (which foreach
is syntactic sugar for):
using( IEnumerator<YourType> e = collection.GetEnumerator() )
{
while( e.MoveNext() )
{
// do something with the item
e.Current ...
}
}
All of the different approaches for enumerating a collection are useful in some specific cases - but it is very contextual as to which pattern to use where.
For instance, using the IEnumerator
object directly is useful where you want fine grained control over exactly how and when to increment and access the iterator. Many LINQ operators internally use IEnumerator
to optimize their implementation.
A reasonable rule of thumb is: that when you are visiting items in order to produce side effects you should use for
or foreach
, when you are transforming (projecting) one sequence into another you should use LINQ (Select, Where, etc...). Using LINQ emphasizes the result while hiding the mechanism, whereas loops emphasizes the mechanism.
Of those you mentioned, the first is preferred. The second one will do a lot more, involving converting to a list and checking for type just to do a foreach in the end anyway.
There are certainly other ways to iterate, but they depend on the collection. For IList
implementations and arrays you can use a normal for
loop and index the items using myitem[i]
.
But there are no reasons not to use foreach since it works for all collections and is AFAIK always the most optimal choise in terms of performance. By optimal I mean in terms of algorithm complexity/big-o
EDIT in response to your question edit
In general, you should use the enumeration scheme that provides the best readability (without seriously impacting performance obviosly). In your example, where you want to see if your list has any elements of a particular type then I would go with the LINQ route (collection.OfType...
). It clearly expresses intent and it's almost possible to read the text in english and get the meaning: "In my collection, get elements of type X and tell me if there are any."
There is Parallel.ForEach:
http://msdn.microsoft.com/en-us/library/dd460720.aspx
Obviously, not converting the collection will be faster than converting it.
I would prefer the first approach because you don't lose the underlying enumerator as you would if you convert to a list. For most collections there's not much difference, but if it's a large collection or one that's being calculated by yielding results, then it could be important.
For some types of collections (like List(Of T)) enumerating via classic foreach
is much faster. This is because foreach
construct in C# does not use IEnumerator and IEnumerable directly.
It calls GetEnumerator() method then calls MoveNext() and Current on object returned. Since List returns ListEnumerator structure which methods are faster when called directly otherwise calling via IEnumerator interface.
精彩评论