How to generate 8 bytes unique id from GUID?

后端 未结 10 1674
长情又很酷
长情又很酷 2020-12-04 01:21

I try to use long as unique id within our C# application (not global, and only for one session) for our events. Do you know if the following will generate an unique long id?

10条回答
  •  青春惊慌失措
    2020-12-04 02:11

    You cannot distill a 16-bit value down to an 8-bit value while still retaining the same degree of uniqueness. If uniqueness is critical, don't "roll your own" anything. Stick with GUIDs unless you really know what you're doing.

    If a relatively naive implementation of uniqueness is sufficient then it's still better to generate your own IDs rather than derive them from GUIDs. The following code snippet is extracted from a "Locally Unique Identifier" class I find myself using fairly often. It makes it easy to define both the length and the range of characters output.

    using System.Security.Cryptography;
    using System.Text;
    
    public class LUID
    {
        private static readonly RNGCryptoServiceProvider RandomGenerator = new RNGCryptoServiceProvider();
        private static readonly char[] ValidCharacters = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789".ToCharArray();
        public const int DefaultLength = 6;
        private static int counter = 0;
    
        public static string Generate(int length = DefaultLength)
        {
            var randomData = new byte[length];
            RandomGenerator.GetNonZeroBytes(randomData);
    
            var result = new StringBuilder(DefaultLength);
            foreach (var value in randomData)
            {
                counter = (counter + value) % (ValidCharacters.Length - 1);
                result.Append(ValidCharacters[counter]);
            }
            return result.ToString();
        }
    }
    

    In this instance it excludes 1 (one), I (i), 0 (zero) and O (o) for the sake of unambiguous human-readable output.

    To determine just how effectively 'unique' your particular combination of valid characters and ID length are, the math is simple enough but it's still nice to have a 'code proof' of sorts (Xunit):

        [Fact]
        public void Does_not_generate_collisions_within_reasonable_number_of_iterations()
        {
            var ids = new HashSet();
            var minimumAcceptibleIterations = 10000;
            for (int i = 0; i < minimumAcceptibleIterations; i++)
            {
                var result = LUID.Generate();
                Assert.True(!ids.Contains(result), $"Collision on run {i} with ID '{result}'");
                ids.Add(result);
            }            
        }
    

提交回复
热议问题