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.

113voto

Ian Boyd Punkte 232380

Leistungsmaßstäbe

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

Regex Pre-Screen:
   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

COM Intertop (am schnellsten) Antwort:

/// <summary>
/// Attempts to convert a string to a guid.
/// </summary>
/// <param name="s">The string to try to convert</param>
/// <param name="value">Upon return will contain the Guid</param>
/// <returns>Returns true if successful, otherwise false</returns>
public static Boolean TryStrToGuid(String s, out Guid value)
{
   //ClsidFromString returns the empty guid for null strings   
   if ((s == null) || (s == ""))   
   {      
      value = Guid.Empty;      
      return false;   
   }

   int hresult = PInvoke.ObjBase.CLSIDFromString(s, out value);
   if (hresult >= 0)
   {
      return true;
   }
   else
   {
      value = Guid.Empty;
      return false;
   }
}

namespace PInvoke
{
    class ObjBase
    {
        /// <summary>
        /// This function converts a string generated by the StringFromCLSID function back into the original class identifier.
        /// </summary>
        /// <param name="sz">String that represents the class identifier</param>
        /// <param name="clsid">On return will contain the class identifier</param>
        /// <returns>
        /// Positive or zero if class identifier was obtained successfully
        /// Negative if the call failed
        /// </returns>
        [DllImport("ole32.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = true)]
        public static extern int CLSIDFromString(string sz, out Guid clsid);
    }
}

Unterm Strich: Wenn Sie prüfen müssen, ob eine Zeichenkette eine Guid ist, und Sie Wert auf Leistung legen, verwenden Sie COM Interop.

Wenn Sie eine Guid in String-Darstellung in eine Guid konvertieren müssen, verwenden Sie

new Guid(someString);

9 Stimmen

Haben Sie diese mit ein- oder ausgeschaltetem Debugger ausgeführt? Die Leistung des Exception Throwing ist um ein Vielfaches besser, wenn der Debugger nicht angeschlossen ist.

0 Stimmen

Ich danke Ihnen. Diese Frage wollte ich auch gerade stellen. Ich bin froh, dass ich Ihre Antwort gefunden habe.

0 Stimmen

Ich habe eine neue Datei namens PInvoke.cs mit dem Namespace PInvoke-Codeausschnitt von oben erstellt, aber ich kann den Code nicht zum Laufen bringen. Wenn ich debugge, sehe ich, dass das Ergebnis von CLSIDFromString IMMER negativ ist. Ich habe versucht, die aufrufende Zeile zu ändern: int hresult = PInvoke.ObjBase.CLSIDFromString(Guid.NewGuid().ToString(), out value); aber es ist immer noch negativ. Was mache ich falsch?

95voto

Sobald .net 4.0 verfügbar ist, können Sie die Guid.TryParse() .

10 Stimmen

Ein noch schnellerer Weg ist die Verwendung der Methode Guid.TryParseExact().

7 Stimmen

Wenn das Parsen von Guid-Strings der langsamste Teil Ihrer Anwendung ist, dann sind Sie gesegnet.

67voto

AnthonyWJones Punkte 182582

Das wird Ihnen nicht gefallen, aber wie kommen Sie darauf, dass das Einfangen der Ausnahme langsamer sein wird?

Wie viele Fehlversuche beim Parsen einer GUID erwarten Sie im Vergleich zu erfolgreichen Versuchen?

Ich empfehle Ihnen, die soeben erstellte Funktion zu verwenden und ein Profil Ihres Codes zu erstellen. Wenn Sie feststellen, dass diese Funktion ein echter Hotspot ist dann reparieren, aber nicht vorher.

2 Stimmen

Gute Antwort: Voreilige Optimierung ist die Wurzel allen Übels.

36 Stimmen

Es ist unangebracht, sich auf Ausnahmen zu berufen, die nicht außergewöhnlich sind. Das ist eine schlechte Angewohnheit, von der ich nicht möchte, dass sie sich jemand aneignet. Und ich würde es vor allem nicht in einer Bibliotheksroutine tun wollen, wo die Leute darauf vertrauen, dass es funktioniert und gut ist.

0 Stimmen

Anonym, in Ihrer ursprünglichen Frage gaben Sie die Leistung als Grund an, warum Sie Ausnahmen vermeiden wollten. Wenn das nicht der Fall ist, sollten Sie Ihre Frage vielleicht anders formulieren.

47voto

zhilia Punkte 1

In .NET 4.0 können Sie wie folgt schreiben:

public static bool IsValidGuid(string str)
{
    Guid guid;
    return Guid.TryParse(str, out guid);
}

4 Stimmen

Dies sollte wirklich eine der wichtigsten Antworten sein.

22voto

Christian.K Punkte 44708

Ich würde es zumindest umformulieren in:

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

Sie wollen nicht "ungültige GUID" bei SEHException, ThreadAbortException oder anderen fatalen oder nicht verwandten Dingen sagen.

Update : Ab .NET 4.0 gibt es einen neuen Satz von Methoden für Guid:

Diese sollten wirklich verwendet werden (schon allein deshalb, weil sie intern nicht "naiv" mit try-catch implementiert sind).

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