/// <summary> /// Generates a unique, sequential, Base36 string; you control the len /// The first 10 characters are the microseconds elapsed since the InService DateTime /// (constant field you hardcode in this file). /// The next 2 characters are a compressed checksum of the MD5 of this host. /// The next 1 character is a reserved constant of 36 ('Z' in Base36). /// The last 3 characters are random number less than 46655 additional for additional uniqueness. /// </summary> /// <returns>Returns a unique, sequential, 16-character Base36 string</returns> public string NewId(bool delimited) { // Keep access sequential so threads cannot accidentally // read another thread's values within this method: // Microseconds since InService (using Stopwatch) provides the // first n chars (n = _numTimestampCharacters): lock (_sb) { _sb.Clear(); long microseconds = ConcurrentStopwatch.GetMicroseconds(); string base36Microseconds = Base36Converter.FromLong(microseconds); if (base36Microseconds.Length > this._numTimestampCharacters) { base36Microseconds = base36Microseconds.Substring(0, this._numTimestampCharacters); } _sb.Append(base36Microseconds.PadLeft(this._numTimestampCharacters, '0')); if (_numServerCharacters > 0) { _sb.Append(_hostHash.Substring(0, _numServerCharacters)); } if (!string.IsNullOrWhiteSpace(this._reservedValue)) { _sb.Append(this._reservedValue); } // Add the random component: _sb.Append(GetRandomBase36DigitsSafe()); if (!delimited || string.IsNullOrWhiteSpace(_delimiter) || this._delimiterPositions == null) { return(_sb.ToString()); } foreach (var pos in this._delimiterPositions) { _sb.Insert(pos, this._delimiter); } return(_sb.ToString()); } }
/// <summary> /// Return the elapsed microseconds since the in-service DateTime; will never /// return the same value twice. Uses a high-resolution Stopwatch (not DateTime.Now) /// to measure durations. /// </summary> /// <returns></returns> internal static long GetMicroseconds() { return(ConcurrentStopwatch.GetMicroseconds()); }