.NET 2.0 introduced Generics to allow enhanced code reusability and type safety. Since then, generic collections (IEnumerable<T>, List<T>, Dictionary<T>, etc.) have become standard and are recommended over their non-generic counterparts (IEnumerable, ArrayList, HashTable, etc.). As a result, Parallel.ForEach only supports generic collections, so code like the following will fail to compile.
IEnumerable nonGenericCollection = …;
Parallel.ForEach(nonGenericCollection, currentElement =>
{
});
This issue applies to all non-generic collections (pretty much anything that was added before .NET 2.0), but here are some usual suspects that we’ve seen folks run into: XmlNodeList, DataRowCollection, DataTableCollection. The error message is typically something like the following:
· “The type arguments for method ‘System.Threading.Tasks.Parallel.ForEach<TSource>) cannot be inferred from the usage. Try specifying the type arguments explicitly.”
· “The best overloaded method match for ‘System.Threading.Tasks.Parallel.ForEach<object>(System.Collections.Generic.IEnumerable<object>, System.Action<object>)’ has some invalid arguments.”
Fortunately, the workaround is simple. Since non-generic collections produce objects (IEnumerator.Current returns Object), it is always possible to produce an IEnumerable<Object> from an IEnumerable. For example:
static IEnumerable<object> Cast(IEnumerable source)
{
foreach (object o in source)
yield return o;
}
Even more fortunately, LINQ already provides this functionality:
public static IEnumerable<TResult>
Cast<TResult>(this IEnumerable source);
So we can easily fix the initial example using this Cast extension method.
using System.Linq;
…
Parallel.ForEach(nonGenericCollection.Cast<object>(),
currentElement =>
{
});
0 comments