C# helper class that generates numbers and IDs sequentially, in a thread-safe manner.
using System;
using System.Threading;
/// <summary>
/// Generates numbers and ids sequentially in a thread-safe manner
/// </summary>
public class SequenceGenerator
{
bool _excludeNegativeNumbers;
long _current;
/// <summary>
/// Initializes a new <see cref="SequenceGenerator"/>
/// </summary>
/// <param name="startValue">Value to start generating sequences from</param>
/// <param name="excludeNegativeNumbers">Set to true to always generate positive numbers, false to include the negative number range</param>
public SequenceGenerator(long startValue, bool excludeNegativeNumbers)
{
if (!excludeNegativeNumbers && startValue < 0) throw new ArgumentException("startValue argument is negative while excludeNegativeNumbers argument is set to true!");
this._excludeNegativeNumbers = excludeNegativeNumbers;
_current = startValue - 1;
}
public static SequenceGenerator FromUtcNow()
{
return new SequenceGenerator(DateTime.UtcNow.Ticks, false);
}
public long GetNext()
{
var val = Interlocked.Increment(ref _current);
if(val < 0 && _excludeNegativeNumbers)
{
do
{
if (Interlocked.CompareExchange(ref _current, 0, val) == val)
{
//Current was successfully set to 0;
val = 0;
break;
}
else
{
//A different thread changed _current, so increment and read again
val = Interlocked.Increment(ref _current);
}
}
while (val < 0);
}
return val;
}
public string GetNextId()
{
return GetNext().ToString("x");
}
}
//
// Usage
//
var correlationIdGen = SequenceGenerator.FromUtcNow();
System.Console.WriteLine(correlationIdGen.GetNextId());
System.Console.WriteLine(correlationIdGen.GetNextId());
//
// Also see <https://github.com/tenor/RestBus/blob/283671e21e53bf3ae275469295baa81d7b388797/src/Brokers/RabbitMQ/RestBus.RabbitMQ/Client/RestBusClient.cs>
// real-world example (line: 16 - `static SequenceGenerator correlationIdGen = SequenceGenerator.FromUtcNow();`)