In response to the solution by Simon and taking into account my notes (see my comments to his answer), here is a solution based on centralized repository which has its benefits:
You can have a value of some numeric type, sufficient to store as many IDs as you may need for the lifetime of the product installation, increment it on each ID generation and store the last value. You can nicely format the result to show some alphanumeric string.
This is an example of such formatting showing the number in hexadecimal format with groups delimited by '-':
static string FormatId(ulong id) {
byte[] serialized = System.BitConverter.GetBytes(id);
object[] parameters =
System.Array.ConvertAll<byte, object>
(serialized, new System.Converter<byte, object>(
(byteValue) => { return byteValue; }
));
return string.Format("NFT#{7:X}{6:X}-{5:X}{4:X}-{3:X}{2:X}-{1:X}{0:X}", parameters);
}
In case you still use C# v.2, this is the version without lambda notation and type inference (but with generics):
static string FormatId(ulong id) {
byte[] serialized = System.BitConverter.GetBytes(id);
object[] parameters =
System.Array.ConvertAll<byte, object>
(serialized, new System.Converter<byte, object>(
delegate(byte byteValue) { return byteValue; }
));
return string.Format("NFT#{7:X}{6:X}-{5:X}{4:X}-{3:X}{2:X}-{1:X}{0:X}", parameters);
}
This is a version of the same thing which might be not so good in performance but might be easier to understand. It also works with C# v.2:
static string FormatId(ulong id) {
byte[] serialized = System.BitConverter.GetBytes(id);
object[] parameters = new object[serialized.Length];
for(int index=0; index < serialized.Length; ++index)
parameters[index] = serialized[index];
return string.Format("NFT#{7:X}{6:X}-{5:X}{4:X}-{3:X}{2:X}-{1:X}{0:X}", parameters);
}
I don't know a simpler way to combine hexadecimal format with custom format specifiers. With decimal base it would simply look:
return "NFT#" + id.ToString("0000-0000-0000-0000")
.
You may want to use shorted strings and less range of IDs. Choose the numeric type and format you prefer and you're done.
[EDIT]
You can make ID generation usable in concurrent environment by using your database in transactional manner, incrementing and returning ID in one transaction. Without a database, you can persist the current numeric value and make the procedure of getting the ID thread-safe using a
lock
.
class IdGenerator {
void Load() { id = }
void Store() { }
static string FormatId(ulong id) { }
string Id {
get {
ulong returnValue;
lock (LockObject) {
returnValue = ++id;
}
return FormatId(returnValue);
}
}
static ulong id;
object LockObject = new object();
}
—SA