0

For Lists I could use the Union method:

var finalCollection = new List<MyType>();
var list1= new List<MyType>();
var list2 = new List<MyType>();
finalCollection = list1.Union(list2).ToList();

But when I try to do the same with ConcurrentBags,

var finalCollection = new ConcurrentBag<MyType>();
var bag1= new ConcurrentBag<MyType>();
var bag2= new ConcurrentBag<MyType>();
finalCollection = bag1.Union(bag2);

I get:

Cannot implicitly convert type "System.Collections.Generic.IEnumerable< MyType>" to "System.Collections.Concurrent.ConcurrentBag"

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
KWC
  • 109
  • 1
  • 8

2 Answers2

3

Perhaps the problem is you are trying to Union the elements into a new ConcurrentBag

What you actually get after the union is an IEnumerable of MyType

To get back a ConcurrentBag try doing it like so:

var bag1 = new ConcurrentBag<MyType>();
var bag2 = new ConcurrentBag<MyType>();
var finalCollection = new ConcurrentBag<MyType>(bag1.Union(bag2));
Rad
  • 8,336
  • 4
  • 46
  • 45
  • I just want to mention that be aware of possible missing items if some items will be added or removed from one of the bags during Union process. ConcurrentBag.GetEnumerator will make a snapshot. https://learn.microsoft.com/en-us/dotnet/api/system.collections.concurrent.concurrentbag-1.getenumerator?view=netframework-4.8 – Support Ukraine Apr 02 '20 at 19:27
  • Thanks. But I think I can't use "new" as I am actually inside a Parallel ForEach loop. The instantiations have already happened outside the loop. – KWC Apr 02 '20 at 20:32
  • @KWC that's not a problem.You can do this instead: finalCollection.AddRange(bag1.Union(bag2)); – Rad Apr 03 '20 at 07:24
  • @Rad , the ConcurrentBag does not seem to have the AddRange method? – KWC Apr 03 '20 at 08:09
  • @KWC my mistake. I had used a list in my sample. I can't think of any other way of populating a pre-created ConcurrentBag other than doing the Union to get an IEnumerable from the first two bags then iterating through that IEnumerable in a loop calling finalCollection.Add() – Rad Apr 03 '20 at 11:29
  • @Rad, Thanks. That's what I did at the end. Was initially just thinking if there is an easy way like the ToList method. Cheers. – KWC Apr 06 '20 at 19:00
1

The var in...

var finalCollection = new ConcurrentBag<MyType>();

...might be hiding what the problem is. Expanding it (mentally or explicitly) to...

ConcurrentBag<MyType> finalCollection = new ConcurrentBag<MyType>();

...should make it clear why bag1.Union(bag2), which returns an IEnumerable<MyType>, can't be assigned to finalCollection. Note that in Visual Studio (Code) if you hover the mouse over the var keyword a tooltip will show you the variable's inferred type.

Also, your two code snippets aren't quite "the same"; in the first you are calling ToList() to create a List<> from the result of Union(), but in the second you trying to assign the result of Union() directly to a ConcurrentBag<> variable without doing anything to actually make it a ConcurrentBag<>, which the other answer shows how to do. If you removed the .ToList() from the first code snippet you would get a similar error.

Lance U. Matthews
  • 15,725
  • 6
  • 48
  • 68
  • Thanks. I have also tried to defined the variable explicitly. But that didn't help. And I am also aware that the thing I did was not quite "the same", that I used `.ToList()`method at the first example. I couldn't find anything like `.ToConcurrentBag()` or something. – KWC Apr 02 '20 at 20:40
  • Changing the variable declaration to `ConcurrentBag finalCollection` wouldn't eliminate the error, it just makes it clear that the type of the variable is more-derived than what you're trying to assign to it, which isn't allowed. – Lance U. Matthews Apr 02 '20 at 20:45