According to the documentation, Take
doesn't return null
if the operation is cancelled: an OperationCanceledException
is thrown instead. Feel free to use any type, and be prepared to handle the exception if needed.
Blocking collections operation and structs
-
02-06-2022 - |
Question
I am using a BlockingCollection with a class of type T and I am wondering if I should turn T into a struct.
From the BlockingCollection signature in principle I do not see problems with that:
[DebuggerDisplay("Count = {Count}, Type = {m_collection}")]
[ComVisible(false)]
[DebuggerTypeProxy(typeof (SystemThreadingCollections_BlockingCollectionDebugView<>))]
[HostProtection(SecurityAction.LinkDemand, ExternalThreading = true, Synchronization = true)]
public class BlockingCollection<T> : IEnumerable<T>, ICollection, IEnumerable, IDisposable
However, the semantic of blocking operation take supporting cancellation is that it returns null if the operation is cancelled before an element becomes available. The problem here is that a structure can't be null, so the following code is invalid
Struct myStruct = collection.Take(cancellationToken);
if(myStruct!=null) ... code
Are therefore blocking collections limited to classes, or does the semantic change returning a non-initialized struct?
Solution
OTHER TIPS
This has more to do with the behavior of structures vs classes. It's not only that a class can't be null, but it's also passed by value, not by reference. This means that each time you access an element of your collection, you'll get a copy of it instead of the original element.
This is the same for all collections, not just the blocking collections.
Regarding Take, as Julien notes, Take throws a OperationCanceledException, it doesn't return a null value. If you want to use Take you'll have to handle the exception whether you use a Struct or a Class.
A better alternative, especially if you expect frequent cancellatins, is to use TryTake instead of Take and check the result. e.g.
Struct myStruct;
if(collection.TryTake(out myStruct))
{
....
}