GuidGenerator.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. using System;
  2. using System.Security.Cryptography;
  3. namespace Ips.Library.Basic
  4. {
  5. public class GuidSeq
  6. {
  7. public static GuidSeq Instance { get; } = new GuidSeq();
  8. private static readonly RandomNumberGenerator Rng = RandomNumberGenerator.Create();
  9. public SequentialGuidDatabaseType DatabaseType { get; set; }
  10. private GuidSeq()
  11. {
  12. DatabaseType = SequentialGuidDatabaseType.PostgreSql;
  13. }
  14. public Guid Create()
  15. {
  16. return Create(DatabaseType);
  17. }
  18. public Guid Create(SequentialGuidDatabaseType databaseType)
  19. {
  20. switch (databaseType)
  21. {
  22. case SequentialGuidDatabaseType.SqlServer:
  23. return Create(SequentialGuidType.SequentialAtEnd);
  24. case SequentialGuidDatabaseType.Oracle:
  25. return Create(SequentialGuidType.SequentialAsBinary);
  26. case SequentialGuidDatabaseType.MySql:
  27. return Create(SequentialGuidType.SequentialAsString);
  28. case SequentialGuidDatabaseType.PostgreSql:
  29. return Create(SequentialGuidType.SequentialAsString);
  30. default:
  31. throw new InvalidOperationException();
  32. }
  33. }
  34. public Guid Create(SequentialGuidType guidType)
  35. {
  36. var randomBytes = new byte[10];
  37. lock (Rng)
  38. {
  39. Rng.GetBytes(randomBytes);
  40. }
  41. long timestamp = DateTime.UtcNow.Ticks / 10000L;
  42. byte[] timestampBytes = BitConverter.GetBytes(timestamp);
  43. if (BitConverter.IsLittleEndian)
  44. {
  45. Array.Reverse(timestampBytes);
  46. }
  47. byte[] guidBytes = new byte[16];
  48. switch (guidType)
  49. {
  50. case SequentialGuidType.SequentialAsString:
  51. case SequentialGuidType.SequentialAsBinary:
  52. Buffer.BlockCopy(timestampBytes, 2, guidBytes, 0, 6);
  53. Buffer.BlockCopy(randomBytes, 0, guidBytes, 6, 10);
  54. if (guidType == SequentialGuidType.SequentialAsString && BitConverter.IsLittleEndian)
  55. {
  56. Array.Reverse(guidBytes, 0, 4);
  57. Array.Reverse(guidBytes, 4, 2);
  58. }
  59. break;
  60. case SequentialGuidType.SequentialAtEnd:
  61. Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 10);
  62. Buffer.BlockCopy(timestampBytes, 2, guidBytes, 10, 6);
  63. break;
  64. }
  65. return new Guid(guidBytes);
  66. }
  67. public enum SequentialGuidDatabaseType
  68. {
  69. SqlServer,
  70. Oracle,
  71. MySql,
  72. PostgreSql,
  73. }
  74. public enum SequentialGuidType
  75. {
  76. SequentialAsString,
  77. SequentialAsBinary,
  78. SequentialAtEnd
  79. }
  80. }
  81. }