2015-05-22 17 views
6

Ich habe eine Anwendung, die eine GUID-Variable hat, die (natürlich) eindeutig sein muss. Ich weiß, dass statistisch jede Guid nur als einzigartig angenommen werden sollte, aber aufgrund von Dev/Test-Umgebungsgründen kann der gleiche Wert mehrmals gesehen werden. Wenn das passiert, möchte ich den Wert des GUID "erhöhen", anstatt nur einen ganz neuen zu erstellen. Es scheint keinen einfachen Weg zu geben, dies zu tun. Ich habe einen Hack gefunden, den ich als mögliche Antwort posten werde, möchte aber eine sauberere Lösung.Inkrementieren Guid in C#

+0

Warum kann es nicht eine neue Guid sein? –

+7

Das ist * nicht * wie 'GUID's * behandelt * werden sollen. Was ist falsch daran, 'Guid.NewGuid()' aufzurufen, wenn Sie eine neue benötigen? –

+0

Die Art, wie Sie dies verwenden, möchten Sie vielleicht stattdessen als UUID bezeichnen. – VoidStar

Antwort

7

Sie können die Byte-Komponenten des guid erhalten, also Sie können sich einfach funktionieren:

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: jetzt mit der richtigen Byte-Reihenfolge

+1

Warum die Downvotes? Möchten Sie erklären, was mit dieser Antwort nicht stimmt? –

+0

Dieser Code löst eine OverflowException mit ++ aus, wenn der Wert des Bytes 255 ist. Daher müsste {} um diese Anweisung herum deaktiviert werden. – Abacus

+0

@Abacus, ist Ihr Projekt mit der Option '/ checked' kompiliert? Ganzzahlarithmetik ist mit den Standardoptionen deaktiviert. –

0

Mögliche Lösung - ich denke, das (nicht funktioniert wirklich getestet), aber eine bessere Lösung wollen.

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: hier ist der Code, ich endete mit; lehnt sich an die obigen Antworten für die allgemeine Technik an, obwohl sie ohne die "unchecked" -Klausel in einigen Fällen Ausnahmen auslösen würden. Aber ich habe auch versucht, das Folgende so leserlich wie möglich zu machen.

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; 
} 
+2

Diese 'if' Kette ist großartig. – Rawling

+2

Die Verwendung von 'BigInteger' zum Inkrementieren führt zu offensichtlich korrektem und wahrscheinlich gut aussehendem Code. –

7

Dank Thomas Levesque ‚s-Byte-Reihenfolge, hier ist eine nette LINQ Implementierung:

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]); 
} 

Hinweis es um zu Guid.Empty hüllt, wenn Sie sich zu erhöhen, so weit zu verwalten.

Es wäre effizienter, wenn Sie eine einzelne Kopie von bytes weiter inkrementieren anstatt ToByteArray nacheinander auf jeder GUID aufzurufen.

+0

Sehr elegant. Sind Sie sich über die Byte-Reihenfolge sicher? –

+0

@ThomasLevesque Es passt zu einigen anderen Orten, die ich gesehen habe. – Rawling

+0

Ich beobachtete diese Reihenfolge: 15, 14, 13, 12, 11, 10, 9, 8, 6, 7, 4, 5, 0, 1, 2, 3 –

1

Verifiziert Lösung für Bestellte Saiten:

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..."); 

    } 

Überprüfung:

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); 
      } 
     } 

    }