189 Stimmen

Testen, ob string eine guid ist, ohne Ausnahmen auszulösen?

Ich möchte versuchen, eine Zeichenkette in eine Guid zu konvertieren, aber ich möchte mich nicht auf das Abfangen von Ausnahmen verlassen (

  • aus Leistungsgründen - Ausnahmen sind teuer
  • aus Gründen der Benutzerfreundlichkeit - der Debugger wird eingeblendet
  • aus gestalterischen Gründen - das Erwartete ist nicht außergewöhnlich

Mit anderen Worten: der Code:

public static Boolean TryStrToGuid(String s, out Guid value)
{
    try
    {
        value = new Guid(s);
        return true;
    }
    catch (FormatException)
    {
        value = Guid.Empty;
        return false;
    }
}

ist nicht geeignet.

Ich würde versuchen, mit RegEx, aber da die guid kann Klammer umschlossen, Klammer umschlossen, keine umschlossen, macht es schwer.

Außerdem dachte ich, dass bestimmte Guid-Werte ungültig sind(?)


Aktualisierung 1

ChristianK hatte eine gute Idee, nur FormatException und nicht alle. Das Code-Beispiel in der Frage wurde geändert, um den Vorschlag aufzunehmen.


Aktualisierung 2

Warum sich über ausgelöste Ausnahmen Gedanken machen? Erwarte ich wirklich so oft ungültige GUIDs?

Die Antwort lautet ja . Deshalb verwende ich TryStrToGuid - ich am in Erwartung schlechter Daten.

Beispiel 1 Namespace-Erweiterungen können durch Anhängen einer GUID an einen Ordnernamen angegeben werden . Ich könnte die Ordnernamen analysieren und prüfen, ob der Text nach dem letzten . ist eine GUID.

c:\Program Files
c:\Program Files.old
c:\Users
c:\Users.old
c:\UserManager.{CE7F5AA5-6832-43FE-BAE1-80D14CD8F666}
c:\Windows
c:\Windows.old

Beispiel 2 Ich könnte einen stark genutzten Webserver betreiben, der die Gültigkeit einiger zurückgesendeter Daten überprüfen möchte. Ich möchte nicht, dass ungültige Daten 2-3 Größenordnungen mehr Ressourcen binden als nötig.

Beispiel 3 Möglicherweise analysiere ich einen von einem Benutzer eingegebenen Suchausdruck.

enter image description here

Wenn sie GUIDs eingeben, möchte ich sie speziell verarbeiten (z. B. speziell nach diesem Objekt suchen oder diesen speziellen Suchbegriff im Antworttext hervorheben und formatieren).


Update 3 - Leistungsvergleiche

Test zur Umwandlung von 10.000 guten und 10.000 schlechten Guids.

Catch FormatException:
   10,000 good:     63,668 ticks
   10,000 bad:   6,435,609 ticks

Regex Pre-Screen with try-catch:
   10,000 good:    637,633 ticks
   10,000 bad:     717,894 ticks

COM Interop CLSIDFromString
   10,000 good:    126,120 ticks
   10,000 bad:      23,134 ticks

p.s. Ich sollte mich für eine Frage nicht rechtfertigen müssen.

0 Stimmen

Ich weiß nicht, die Antwort auf diese ein, aber für was es wert ist, Sie haben Recht, nicht zu wollen, ein Try/Catch-Block hier zu verwenden. Es braucht eine Menge Berechnungen, um die Kosten für das Abfangen einer Ausnahme aufzuwiegen, und try/catch ist nicht für einen normalen Programmablauf geeignet! Natürlich nur, wenn Sie nicht viele Ausnahmen in diesem Code abfangen müssen, es ist nicht wirklich eine große Sache .

7 Stimmen

Warum in aller Welt ist dies ein Gemeinschafts-Wiki?

38 Stimmen

Sie haben Recht, Sie sollten no eine Frage rechtfertigen müssen. Dennoch habe ich die Begründung mit Interesse gelesen (da sie dem Grund, warum ich dies hier lese, sehr ähnlich ist). Also, danke für die tolle Begründung.

14voto

Mark Brackett Punkte 83046

Interop ist langsamer als das einfache Abfangen der Ausnahme:

Auf dem glücklichen Weg, mit 10.000 Guids:

Exception:    26ms
Interop:   1,201ms

Auf dem unglücklichen Weg:

Exception: 1,150ms
  Interop: 1,201ms

Sie ist konsistenter, aber auch durchweg langsamer. Scheint mir, Sie wären besser dran, wenn Sie Ihren Debugger so konfigurieren, dass er nur bei unbehandelten Ausnahmen abbricht.

0 Stimmen

"Ihr Debugger soll nur bei unbehandelten Ausnahmen abbrechen" Keine Option.

1 Stimmen

@Ian Boyd - Wenn Sie eine der VS-Editionen (einschließlich Express) verwenden, ist es es eine Option. msdn.microsoft.com/de-us/library/038tzxdw.aspx .

1 Stimmen

Ich meinte, es ist keine machbare Option. Wie: "Scheitern ist keine Option." Es es eine Option, die ich aber nicht nutzen werde.

10voto

pdavis Punkte 3174

Nun, hier ist die Regex, die Sie benötigen...

^[A-Fa-f0-9]{32}$|^({|\\()?[A-Fa-f0-9]{8}-([A-Fa-f0-9]{4}-){3}[A-Fa-f0-9]{12}(}|\\))?$|^({)?[0xA-Fa-f0-9]{3,10}(, {0,1}[0xA-Fa-f0-9]{3,6}){2}, {0,1}({)([0xA-Fa-f0-9]{3,4}, {0,1}){7}[0xA-Fa-f0-9]{3,4}(}})$

Aber das ist nur der Anfang. Sie müssen auch überprüfen, ob die verschiedenen Teile wie Datum und Uhrzeit innerhalb akzeptabler Bereiche liegen. Ich kann mir nicht vorstellen, dass dies schneller geht als die Try/Catch-Methode, die Sie bereits skizziert haben. Hoffentlich erhalten Sie nicht so viele ungültige GUIDs, dass diese Art der Überprüfung gerechtfertigt ist!

0 Stimmen

Ähm, IIRC GUIDs, die aus einem Zeitstempel generiert werden, werden im Allgemeinen als schlechte Idee angesehen und die andere Art (Typ 4) ist völlig willkürlich

6voto

JMD Punkte 1408

aus Gründen der Benutzerfreundlichkeit - der Debugger wird eingeblendet

Wenn Sie sich für den try/catch-Ansatz entscheiden, können Sie das Attribut [System.Diagnostics.DebuggerHidden] hinzufügen, um sicherzustellen, dass der Debugger nicht abbricht, selbst wenn Sie ihn so eingestellt haben, dass er bei einem Wurf abbricht.

5voto

Josef Punkte 7227

Während es es Es stimmt zwar, dass die Verwendung von Fehlern teurer ist, aber die meisten Leute glauben, dass die meisten ihrer GUIDs computergeneriert sein werden, so dass eine TRY-CATCH ist nicht zu teuer, da es nur Kosten für die CATCH . Dies können Sie selbst mit einem einfachen Test der zwei (Benutzer öffentlich, kein Passwort).

Hier ist es:

using System.Text.RegularExpressions;

 /// <summary>
  /// Validate that a string is a valid GUID
  /// </summary>
  /// <param name="GUIDCheck"></param>
  /// <returns></returns>
  private bool IsValidGUID(string GUIDCheck)
  {
   if (!string.IsNullOrEmpty(GUIDCheck))
   {
    return new Regex(@"^(\{{0,1}([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}\}{0,1})$").IsMatch(GUIDCheck);
   }
   return false;
  }

5voto

JBrooks Punkte 9570

Ich hatte eine ähnliche Situation, und mir ist aufgefallen, dass die ungültige Zeichenfolge fast nie 36 Zeichen lang war. Auf der Grundlage dieser Tatsache habe ich Ihren Code ein wenig geändert, um eine bessere Leistung zu erzielen und ihn dennoch einfach zu halten.

public static Boolean TryStrToGuid(String s, out Guid value)
{

     // this is before the overhead of setting up the try/catch block.
     if(value == null || value.Length != 36)
     {  
        value = Guid.Empty;
        return false;
     }

    try
    {
        value = new Guid(s);
        return true;
    }
    catch (FormatException)
    {
        value = Guid.Empty;
        return false;
    }
}

1 Stimmen

Guid akzeptiert mehr als nur die gestrichelte Stringform in seinem ctor. GUIDs können geschweifte Klammern mit Bindestrichen haben oder ohne Bindestriche oder Klammern sein. Dieser Code erzeugt falsch-negative Ergebnisse, wenn er von diesen alternativen, aber ebenfalls vollkommen gültigen String-Formen verwendet wird.

1 Stimmen

Die gültigen Längen für GUIDs in Stringform sind 32, 36 und 38 - reine Hexadezimalzahlen, gestrichelte Zahlen und Klammern mit Bindestrichen.

1 Stimmen

@Chris, Ihr Argument ist stichhaltig, aber @JBrooks Idee, die voraussichtliche GUID auf ihre Unbedenklichkeit zu prüfen, bevor man sich in try/catch stürzt, ist sinnvoll, insbesondere wenn verdächtige Eingaben häufig vorkommen. Vielleicht so etwas wie if( value==null || value.Length < 30 || value.length > 40 ) {value=Guid.Empty;return false;}

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X