1

I have an UnboundedChannel single reader\multiple writers and I want to be able to use Count property, but since CanCount property is always false Count is throwing an exception. What should i do to make it work, i can't find any restrictions enlisted in docs.

Tiny Wang
  • 10,423
  • 1
  • 11
  • 29
cookieMonster
  • 508
  • 6
  • 15
  • Why do you want to know that? Whatever the actual problem is probably doesn't require knowing the count. For example, to batch messages you can retrieve them one by one and add them to a local list until you reach the limit. You could also use the LINQ operators in the [System.Linq.Async](https://www.nuget.org/packages/System.Linq.Async/) package along with `ChannelReader.ReadAllAsync()`, – Panagiotis Kanavos Dec 17 '21 at 12:26

2 Answers2

4

When the UnboundedChannelOptions.SingleReader property is set to true on creation, the UnboundedChannel implementation is SingleConsumerUnboundedChannel. Based on the source, the Reader object used by this class extends ChannelReader without explicitly setting CanCount, which is set to false by ChannelReader by default.

Unfortunately all these classes are sealed so you can't just extend them and implement Count yourself. Leaving the SingleReader option as false will use an UnboundedChannelReader implementation that does set CanCount to true and implements a Count method. If you just need to check whether there are more elements in the queue, you could also use TryPeek instead.

IllusiveBrian
  • 3,105
  • 2
  • 14
  • 17
  • Thanks, i haven't noticed i was acutally using SingleConsumerUnboundedChannel in this configuration, now with default options it works. I wonder why CanCount set to false with single reader. – cookieMonster Dec 17 '21 at 09:09
  • @cookieMonster The implementation of [`SingleProducerConsumerQueue`](https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/Common/src/System/Collections/Concurrent/SingleProducerConsumerQueue.cs) implements `Count` but says "This method is not safe to use concurrently with any other members that may mutate the collection." My best guess is that the designers decided not to expose it rather than open up the concurrency error risk. – IllusiveBrian Dec 17 '21 at 12:56
2

All bounded channel implementations support reading the Count, so if you need a SingleReader and Count-enabled unbounded channel you could just use a bounded channel configured with the maximum capacity. Practically it will be unbounded.

var channel = Channel.CreateBounded<int>(
    new BoundedChannelOptions(Int32.MaxValue) { SingleReader = true });

Console.WriteLine(channel.Reader.CanCount); // True

Update: Currently there is only one bounded channel implementation, the BoundedChannel<T> (internal sealed class), which ignores the SingleReader setting. In other words you get the same implementation, regardless of the number of readers that you want to use. Which is a bit disappointing, because it indicates that the rich set of available options does not correspond to an equally rich set of implementations. Basically there are only three implementations available in .NET 6, the UnboundedChannel<T>, the SingleConsumerUnboundedChannel<T>, and the BoundedChannel<T>.

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104