Increment Guid in C#

后端 未结 4 748
一向
一向 2021-01-17 18:32

I have an application that has a guid variable which needs to be unique (of course). I know that statistically any guid should just be assumed to be unique, but due to dev/t

相关标签:
4条回答
  • 2021-01-17 18:37

    You can get the byte components of the guid, so you can just work on that:

    static class GuidExtensions
    {
        private static readonly int[] _guidByteOrder =
            new[] { 15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3 };
        public static Guid Increment(this Guid guid)
        {
            var bytes = guid.ToByteArray();
            bool carry = true;
            for (int i = 0; i < _guidByteOrder.Length && carry; i++)
            {
                int index = _guidByteOrder[i];
                byte oldValue = bytes[index]++;
                carry = oldValue > bytes[index];
            }
            return new Guid(bytes);
        }
    }
    

    EDIT: now with correct byte order

    0 讨论(0)
  • 2021-01-17 18:40

    Thanks to Thomas Levesque's byte order, here's a nifty LINQ implementation:

    static int[] byteOrder = { 15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3 };
    
    static Guid NextGuid(Guid guid)
    {
        var bytes = guid.ToByteArray();
        var canIncrement = byteOrder.Any(i => ++bytes[i] != 0);
        return new Guid(canIncrement ? bytes : new byte[16]);
    }
    

    Note it wraps around to Guid.Empty if you manage to increment it that far.

    It would be more efficient if you were to keep incrementing a single copy of bytes rather than calling ToByteArray on each GUID in turn.

    0 讨论(0)
  • 2021-01-17 18:45

    Verified Solution for Ordered Strings:

        private static Guid Increment(Guid guid)
        {
    
            byte[] bytes = guid.ToByteArray();
    
            byte[] order = { 15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3 };
    
            for (int i = 0; i < 16; i++)
            {
                if (bytes[order[i]] == byte.MaxValue)
                {
                    bytes[order[i]] = 0;
                }
                else
                {
                    bytes[order[i]]++;
                    return new Guid(bytes);
                }
            }
    
            throw new OverflowException("Congratulations you are one in a billion billion billion billion etc...");
    
        }
    

    Verification:

        private static Guid IncrementProof(Guid guid, int start, int end)
        {
    
            byte[] bytes = guid.ToByteArray();
    
            byte[] order = { 15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3 };
    
            for (int i = start; i < end; i++)
            {
                if (bytes[order[i]] == byte.MaxValue)
                {
                    bytes[order[i]] = 0;
                }
                else
                {
                    bytes[order[i]]++;
                    return new Guid(bytes);
                }
            }
    
            throw new OverflowException("Congratulations you are one in a billion billion billion billion etc...");
    
        }
    
        static void Main(string[] args)
        {
    
            Guid temp = new Guid();
    
            for (int j = 0; j < 16; j++)
            {
                for (int i = 0; i < 255; i++)
                {
                    Console.WriteLine(temp.ToString());
                    temp = IncrementProof(temp, j, j + 1);
                }
            }
    
        }
    
    0 讨论(0)
  • 2021-01-17 19:00

    Possible solution -- I think this works (not really tested), but want a better solution.

    public static Guid Increment(this Guid value)
    {
        var bytes = value.ToByteArray();
        // Note that the order of bytes in the returned byte array is different from the string representation of a Guid value.
        //  Guid:       00112233-4455-6677-8899-aabbccddeeff
        //  byte array: 33 22 11 00 55 44 77 66 88 99 AA BB CC DD EE FF
        // So the byte order of the following indexes indicates the true low-to-high sequence
        if (++bytes[15] == 0) if (++bytes[14] == 0) if (++bytes[13] == 0) if (++bytes[12] == 0) if (++bytes[11] == 0) if (++bytes[10] == 0) // normal order
         if (++bytes[9] == 0) if (++bytes[8] == 0) // normal order
          if (++bytes[6] == 0) if (++bytes[7] == 0) // reverse order
           if (++bytes[5] == 0) if (++bytes[4] == 0) // reverse order
            if (++bytes[3] == 0) if (++bytes[2] == 0) if (++bytes[1] == 0) { ++bytes[0]; } // reverse order
        return new Guid(bytes);
    }
    

    Edit: here is the code I ended up using; props to the answers above for the general technique, although without the "unchecked" clause they both would throw exceptions in some cases. But I also tried to make the below as readable as possible.

    private static int[] _guidByteOrder = { 15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3 };
    public static Guid NextGuid(this Guid guid)
    {
        var bytes = guid.ToByteArray();
        for (int i = 0; i < 16; i++)
        {
            var iByte = _guidByteOrder[i];
            unchecked { bytes[iByte] += 1; }
            if (bytes[iByte] != 0)
                return new Guid(bytes);
        }
        return Guid.Empty;
    }
    
    0 讨论(0)
提交回复
热议问题