0

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.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
MichaelS
  • 171
  • 11
  • Change the statement as `Parallel.ForEach(ObjectDict["Object A"], (ObjectA objA) =>` – user1672994 Aug 19 '21 at 06:31
  • When doing this I get the following Error: Code CS1503 Argument 1: cannot convert from System.Collections.Concurrent.ConcurrentBag to System.Collections.Concurrent.OrderablePartitioner – MichaelS Aug 19 '21 at 06:38
  • Please share a [mcve] including your existing working `foreach` code. – mjwills Aug 19 '21 at 07:13
  • found a solution. please see my answer below – MichaelS Aug 19 '21 at 07:17
  • As a side note, if I was in your shoes I wouldn't use a `ConcurrentDictionary>`. The `ConcurrentBag` is a [very specialized](https://stackoverflow.com/questions/15400133/when-to-use-blockingcollection-and-when-concurrentbag-instead-of-listt/64823123#64823123) collection. Probably `ConcurrentDictionary>` would be my preference. – Theodor Zoulias Aug 19 '21 at 08:22

2 Answers2

2

You can specify the type, just as you can do in your regular foreach:

    Parallel.ForEach(ObjectDict["Object A"], (ObjectsA objectA) =>
    {
         objectA.ObjectASpecificMethod();
    }
nvoigt
  • 75,013
  • 26
  • 93
  • 142
  • When doing this I get the following Error: Code CS1503 Argument 1: cannot convert from System.Collections.Concurrent.ConcurrentBag to System.Collections.Concurrent.OrderablePartitioner – MichaelS Aug 19 '21 at 06:37
1

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.

MichaelS
  • 171
  • 11
  • 1
    See [When to use Cast() and Oftype() in Linq](https://stackoverflow.com/questions/4015930/when-to-use-cast-and-oftype-in-linq) – Theodor Zoulias Aug 19 '21 at 08:17
  • `Even though all Objects in the ConcurrentBag are of the same object type it is handled as a non-generic collection.` That is not true. It is definitely, 100%, handled as a generic collection. It might not be the type you _expected_ - but it is definitely 100% a generic collection. – mjwills Aug 19 '21 at 08:37
  • I mean I agree. Otherwise simple foreach loop would have problems cycling aswell, no? but why do i get the error then if not due to the fact that it is not generic and therefore generic methods are throwing errors? – MichaelS Aug 19 '21 at 11:21
  • 1
    `but why do i get the error then` Because if you `Parallel.ForEach` over a List, the type of the variable is of type T. `foreach` lets you "cheat" by having the variable be a different type. If you changed `ObjectA` to `var` in your `foreach` you would have the exact same issue. – mjwills Aug 19 '21 at 11:36