Search code examples
c#inheritanceforeachparallel.foreachconcurrentdictionary

Parallel.Foreach on values (Concurrent Bag) of one key in Concurrent Dictionary


I am having problems converting a ForEach loop into a Parallel.ForEach loop.

I have a Concurrent Dictionary:

private readonly ConcurrentDictionary<string, ConcurrentBag<ParentClass>> ObjectDict = new();

which contains:

  • as key: string of object "type"
  • as value: a ConcurrentBag of objects of a class which inherited from ParentClass. In the following code it shall be ObjectA.

Object A inherits from ParentClass.

My goal is to cycle through the Concurrent Bag of one Key-Entry in the Concurrent Dictionary.

Now I am struggling to convert the following ForEach Loop to Parallel.ForEach

foreach (ObjectA objA in ObjectDict["Object A"])
{
     objA.ObjectASpecificMethod();
}

To

Parallel.ForEach(ObjectDict["Object A"], objA =>
{
     objA.ObjectASpecificMethod();
}

The problem is that objA is not of type ObjectA but of ParentClass as defined in the Concurrent Dictionary ObjectDict. But ParentClass does not have the Childclass specific Method.

I hope I could clarify myself properly.


Solution

  • Found the Problem: Even though all Objects in the ConcurrentBag are of the same object type it is handled as a non-generic collection. This might be a because the ConcurrentBag is specified as ParentClass, but the Objects inside are of ChildClass.

    To fix this Problem I found 2 ways:

    1. Casting the correct object type like described here: https://devblogs.microsoft.com/pfxteam/faq-parallel-foreach-and-non-generic-collections/

      Parallel.ForEach(ObjectDict["Object A"].Cast<ObjectA>(), objA =>
      {
            objA.ObjectASpecificMethod();
      }
      
    2. Specifying the type of the non-generic collection with the correct objecttype

      Parallel.ForEach(ObjectDict["Object A"].OfType<ObjectA>(), objA =>
      {
           objA.ObjectASpecificMethod();
      }
      

    For both methods to work you need to be using System.Linq!

    Tested both and they both seem to provide valid results. Maybe someone more knowledgeable can elaborate on the differences.