Boost Your .NET Projects: Ensure Thread-Safe Uniqueness with DistinctConcurrentBag in Spargine

Spargine is a collection of open-source assemblies and NuGet packages designed for .NET 10, which I have been developing and maintaining since the release of .NET Framework 2. These assemblies are not only a core part of my projects but are also actively deployed in production environments across several companies I collaborate with.

Get Spargine

You can access the source code and NuGet packages here:

When working with concurrent collections in .NET, ConcurrentBag<T> is a popular and reliable choice for handling unordered, thread-safe data. However, there’s one major limitation — it doesn’t enforce uniqueness. If the same item is added twice, it happily stores both.

If your application requires a thread-safe collection that automatically prevents duplicates, Spargine delivers the solution.

Introducing DistinctConcurrentBag<T>

DistinctConcurrentBag<T> provides a thread-safe, unordered collection of unique elements. It ensures that only distinct items are stored — while still supporting atomic add, remove, and enumeration operations just like other concurrent collections.

This makes it ideal for scenarios such as:

  • background processing queues
  • caching pipelines
  • deduplicating producer–consumer workflows
  • telemetry aggregation
  • concurrent ID or reference management

All without the overhead and complexity of manually tracking uniqueness yourself.

DistinctConcurrentBag is located in the DotNetTips.Spargine.Core assembly and NuGet package.

Constructors

You can create a DistinctConcurrentBag<T> in several ways depending on your needs:

  • DistinctConcurrentBag()
    Initializes a new, empty instance.
  • DistinctConcurrentBag(IEnumerable<T> collection)
    Initializes the bag and preloads it with items from a collection.
  • DistinctConcurrentBag(IEqualityComparer<T> comparer)
    Uses a custom comparer to control equality logic — perfect for case-insensitive strings or complex objects.

Available Members & Behavior

Add & Remove Operations

  • Add(T item)
    Adds an item — only if it doesn’t already exist.
  • TryAdd(T item)
    Attempts to add an item, returning true only if it was successfully added.
  • AddRange(IEnumerable<T> items)
    Adds multiple items while enforcing uniqueness.
  • Remove(T item)
    Removes the specified item.
  • RemoveRange(IEnumerable<T> items)
    Removes multiple items at once.
  • TryTake(out T result)
    Attempts to remove and return an item from the bag.

Lookup & Existence Checks

  • Contains(T item)
    Determines whether the item exists.
  • ContainsAny(IEnumerable<T> items)
    Returns true if any of the given items exist in the bag.
  • TryGetValue(T equalValue, out T actualValue)
    Retrieves the canonical stored instance of an equal item — ideal for memory-sharing or identity-preserving patterns.
  • TryPeek(T equalValue, out T actualValue)
    Attempts to look up (without removing) a matching item.

Enumeration & Conversion

  • ToArray()
    Copies elements into a new array.
  • CopyTo(T[] array, int arrayIndex)
    Copies elements to an existing array starting at the given index.
  • ToList()
    Converts the bag to a List<T>.
  • ToFrozenSet()
    Converts the bag to a FrozenSet<T> for ultra-fast immutable lookup and enumeration.

State & Metadata

  • Count
    Gets the total number of elements.
  • IsEmpty
    Indicates whether the bag contains any elements.
  • IsReadOnly
    Indicates whether the collection is read-only.
  • Clear()
    Removes all items.

Why Use DistinctConcurrentBag<T>?

Because it gives you the best of both worlds:

  • Thread safety — without locks in your code
  • Guaranteed uniqueness — without extra bookkeeping
  • Low-friction integration — familiar ConcurrentBag-style API

If you’ve ever:

  • struggled with duplicates appearing unexpectedly
  • wrapped a concurrent collection and a HashSet together
  • added costly locking just to enforce uniqueness

…then DistinctConcurrentBag<T> cleans all that up beautifully.

Need Blocking Behavior Too?

If you need producer–consumer coordination plus enforced uniqueness, Spargine also includes:

DistinctBlockingCollection<T>

It pairs the uniqueness enforcement of DistinctConcurrentBag<T> with the blocking semantics of BlockingCollection<T>, perfect for pipeline processing.

Summary

If you need a thread-safe collection that guarantees uniqueness by design, DistinctConcurrentBag<T> in Spargine is a powerful, high-performance choice. It eliminates duplicate-handling logic while maintaining the simplicity and safety of concurrent collections.

And when you also need blocking behavior — reach for DistinctBlockingCollection<T>. Together, these tools make your concurrent .NET programming cleaner, safer, and more efficient.

Rock your code. Ship with confidence.

Get Involved!

The success of open-source projects like Spargine relies on community contributions. If you find these updates useful or have ideas for further improvements, I encourage you to contribute by:

  • Submitting pull requests
  • Reporting issues
  • Suggesting new features

Your input is invaluable in making Spargine an even more powerful tool for the .NET community.

If you are interested in contributing or have any questions, feel free to contact me via email at dotnetdave@live.com. Your support and collaboration are greatly appreciated!

Thank you, and happy coding!

Pick up any books by David McCarter by going to Amazon.com: http://bit.ly/RockYourCodeBooks

One-Time
Monthly
Yearly

Make a one-time donation

Make a monthly donation

Make a yearly donation

Choose an amount

$5.00
$15.00
$100.00
$5.00
$15.00
$100.00
$5.00
$15.00
$100.00

Or enter a custom amount

$

Your contribution is appreciated.

Your contribution is appreciated.

Your contribution is appreciated.

DonateDonate monthlyDonate yearly

If you liked this article, please buy David a cup of Coffee by going here: https://www.buymeacoffee.com/dotnetdave

© The information in this article is copywritten and cannot be preproduced in any way without express permission from David McCarter.


Discover more from dotNetTips.com

Subscribe to get the latest posts sent to your email.

One thought on “Boost Your .NET Projects: Ensure Thread-Safe Uniqueness with DistinctConcurrentBag in Spargine

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.