Napisałem zajęcia specjalnie w tym celu. Jest inicjowany częścią „podstawową” (domyślnie jest to znacznik czasu z dokładnością co do minuty), a następnie dołącza litery, aby utworzyć unikalne nazwy. Tak więc, jeśli pierwszy wygenerowany znaczek to 1907101215a, drugi to 1907101215b, następnie 1907101215c i tak dalej.
Jeśli potrzebuję więcej niż 25 unikalnych znaczków, używam jednoargumentowych „z”, aby policzyć 25. Więc to idzie 1907101215y, 1907101215za, 1907101215zb, ... 1907101215zy, 1907101215zza, 1907101215zzb i tak dalej. Gwarantuje to, że znaczki zawsze będą sortowane alfanumerycznie w kolejności, w jakiej zostały wygenerowane (o ile następny znak po znaczku nie jest literą).
Nie jest bezpieczny dla wątków, nie aktualizuje automatycznie czasu i szybko się rozrasta, jeśli potrzebujesz setek znaczków, ale uważam, że jest wystarczający dla moich potrzeb.
public class StampGenerator
{
private static readonly char[] _trailingChars =
{
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y'
};
public const int TRAILING_RANGE = 25;
public const int MAX_LENGTH_STAMP = 28;
public string StampBase { get; }
public int CalledTimes { get; private set; }
public int MaxCalls { get; }
public int RemainingCalls { get { return MaxCalls - CalledTimes; } }
public StampGenerator(string stampBase, int calledTimes = 0)
{
if (stampBase == null)
{
throw new ArgumentNullException("stampBase");
}
else if (Regex.IsMatch(stampBase, "[^a-zA-Z_0-9 \\-]"))
{
throw new ArgumentException("Invalid characters in Stamp Base.",
"stampBase");
}
else if (stampBase.Length >= MAX_LENGTH_STAMP - 1)
{
throw new ArgumentException(
string.Format("Stamp Base too long. (Length {0} out of {1})",
stampBase.Length, MAX_LENGTH_STAMP - 1), "stampBase");
}
else if (calledTimes < 0)
{
throw new ArgumentOutOfRangeException(
"calledTimes", calledTimes, "calledTimes cannot be negative.");
}
else
{
int maxCalls = TRAILING_RANGE * (MAX_LENGTH_STAMP - stampBase.Length);
if (calledTimes >= maxCalls)
{
throw new ArgumentOutOfRangeException(
"calledTimes", calledTimes, string.Format(
"Called Times too large; max for stem of length {0} is {1}.",
stampBase.Length, maxCalls));
}
else
{
StampBase = stampBase;
CalledTimes = calledTimes;
MaxCalls = maxCalls;
}
}
}
public StampGenerator() : this(DateTime.Now.ToString("yMMddHHmm")) { }
public override string ToString()
{
int zCount = CalledTimes / TRAILING_RANGE;
int trailing = CalledTimes % TRAILING_RANGE;
int length = StampBase.Length + zCount + 1;
if (length > MAX_LENGTH_STAMP)
{
throw new InvalidOperationException(
"Stamp length overflown! Cannot generate new stamps.");
}
else
{
CalledTimes = CalledTimes + 1;
var builder = new StringBuilder(StampBase, length);
builder.Append('z', zCount);
builder.Append(_trailingChars[trailing]);
return builder.ToString();
}
}
}