Frage

Ich will versuchen, eine Zeichenfolge in eine Guid zu konvertieren, aber ich will nicht auf den Fang Ausnahmen verlassen (

  • aus Leistungsgründen - Ausnahmen sind teuer
  • für die Benutzerfreundlichkeit Gründen - der Debugger erscheint
  • aus Designgründen - die 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, RegEx verwenden, aber da die guid Klammer gewickelt werden kann, Klammer gewickelt, keine gehüllt, macht es schwer.

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


Update 1

ChristianK hatte ein gute Idee, nur FormatException, anstatt alle zu fangen. Geändert, um das Codebeispiel Frage Vorschlag aufzunehmen.


Update 2

Warum über geworfene Ausnahmen Sorgen machen? Erwarte ich wirklich ungültig GUIDs alles, was oft?

Die Antwort ist ja . Deshalb habe ich TryStrToGuid bin mit -. I am erwarten schlechte Daten

Beispiel 1 Namespace-Erweiterungen kann durch Anhängen einer GUID zu einem Ordnernamen angegeben werden. Ich könnte Ordnernamen werden Parsen, um zu sehen, zu überprü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 ein stark genutzte Web-Server will die Gültigkeit einiger zurückgesendet Daten ausgeführt werden, überprüfen. Ich möchte nicht, ungültige Daten Ressourcen binden 2-3 Größenordnungen höher als es sein muss.

Beispiel 3 Ich könnte einen Suchausdruck von einem Benutzer eingegeben werden Parsen.

eingeben Bild Beschreibung hier

Wenn sie GUID eingeben möchte ich sie speziell verarbeiten (wie speziell für das Objekt, oder markieren und formatieren, die bestimmten Suchbegriff in der Antworttext.)


Update 3 - Performance-Benchmarks

Test Umwandlung 10.000 gute Guids und 10.000 schlechte 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 nicht eine Frage zu rechtfertigen haben.

War es hilfreich?

Lösung

Performance-Benchmarks

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

Fazit: Wenn Sie überprüfen müssen, ob eine Zeichenfolge ein guid ist, und Sie kümmern sich um Leistung verwenden Sie COM-Interop.

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

new Guid(someString);

Andere Tipps

Sobald .net 4.0 verfügbar ist, können Sie a href verwenden <= "https://msdn.microsoft.com/en-us/library/system.guid.tryparse(v=vs.110).aspx" rel = "noreferrer"> Guid.TryParse() .

Du wirst nicht auf diese Weise aber was macht Sie denken, dass die Ausnahme abfangen wird langsamer sein?

Wie viele gescheiterte Versuche eine GUID zu analysieren erwarten Sie im Vergleich zu Erfolgreichen?

Mein Rat ist, die Funktion verwenden Sie gerade erstellt haben und Ihr Code profilieren. Wenn Sie feststellen, dass diese Funktion wirklich ein Hotspot ist und fixiert, jedoch nicht vor.

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

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

Ich würde zumindest umschreiben als:

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

Sie wollen nicht „ungültig GUID“ auf SEHException, Threadabort oder andere tödlichen oder nicht-verwandte Themen sagen.

Aktualisieren : Beginnend mit .NET 4.0 gibt es eine neue Reihe von Methoden zur Verfügung, für Guid:

Wirklich, sollten diese verwendet werden (wenn auch nur für die Tatsache, dass sie nicht „naiv“ implementiert Try-Catch-intern).

Interop ist langsamer als nur die Ausnahme abfangen:

In dem glücklichen Weg, mit 10.000 Guids:

Exception:    26ms
Interop:   1,201ms

In dem unglücklichen Pfad:

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

Es ist konsequenter, aber es ist auch konsequent langsamer. Scheint mir, Sie wären besser dran, Ihre Debugger Konfiguration nur auf nicht behandelte Ausnahmen zu brechen.

Nun, hier ist die regex 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 sicherstellen, dass die verschiedenen Teile wie Datum / Uhrzeit innerhalb akzeptabler Bereiche. Ich kann mir nicht vorstellen, dass diese schneller als die try / catch-Methode ist, dass Sie bereits skizziert haben. Hoffentlich werden Sie nicht erhalten, dass viele ungültige GUIDs diese Art der Überprüfung zu rechtfertigen!

  

für die Benutzerfreundlichkeit Gründen - der Debugger erscheint

Wenn Sie sich für den Try / Catch-Ansatz gehen Sie hinzufügen können Sie die [System.Diagnostics.DebuggerHidden] Attribut um sicherzustellen, dass der Debugger nicht einmal brechen, wenn Sie es auf Wurf zu brechen festgelegt haben.

Während es ist wahr, dass Fehler mit teurer ist, glauben die meisten Menschen, dass ein Großteil ihrer GUIDs werden Computer generiert werden, so dass ein TRY-CATCH nicht zu teuer ist, da es nur auf Kosten erzeugt die CATCH. Sie können dies mit einem einfachen Test des zwei (Benutzer öffentlich, kein Passwort).

Hier gehen Sie:

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

Ich hatte eine ähnliche Situation, und ich bemerkte, dass so gut wie nie die ungültige Zeichenfolge 36 Zeichen lang war. So basiert auf dieser Tatsache änderte ich Ihren Code ein wenig bessere Leistung zu erhalten, während es immer noch 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;
    }
}

Soweit ich weiß, gibt es keine so etwas wie Guid.TryParse in mscrolib. Laut Referenzquelle hat Guid Typ Mega-Komplex Konstruktor, der alle Arten von guid Formaten überprüft und versucht, sie zu analysieren. Es gibt keine Hilfsmethode Sie anrufen können, auch über Reflexion. Ich glaube, Sie für 3rd-Party-Guid Parser zu suchen haben, oder schreiben Sie Ihre eigenen.

Führen Sie das Potential GUID obwohl ein RegEx oder einige benutzerdefinierte Code, der tut eine Plausibilitätsprüfung der strig zumindest sieht aus wie eine GUID und besteht nur aus gültigen Zeichen zu gewährleisten (und vielleicht auch, dass es das Gesamtformat zu passen scheint). Wenn es nicht die Plausibilitätsprüfung nicht besteht einen Fehler zurück -. Das wird wahrscheinlich die große Mehrheit der ungültigen Strings auszusondern

Dann die Zeichenfolge konvertieren, wie Sie oben haben, nach wie vor die Ausnahme für die wenige ungültigen Strings zu kontrollieren, die durch die Plausibilitätsprüfung erhalten.

Jon Skeet eine Analyse für etwas ähnliches tat Ints zum Parsen (vor TryParse im Rahmen war): Überprüfen, ob eine Zeichenfolge umgewandelt werden, um Int32

Wie jedoch AnthonyWJones angegeben sollten Sie wahrscheinlich nicht darüber Sorgen machen.

 bool IsProbablyGuid(string s)
    {
        int hexchars = 0;
        foreach(character c in string s)
        {
           if(IsValidHexChar(c)) 
               hexchars++;          
        }
        return hexchars==32;
    }
  • Get Reflector
  • copy'n'paste GUIDs .ctor (String)
  • ersetzt alle Vorkommen von „neuen werfen ...“ mit „return false“.

GUIDs Ctor ist so ziemlich eine kompilierte Regex, auf diese Weise Sie genau ohne Overhead der Ausnahme das gleiche Verhalten erhalten werden.

  1. stellt dies ein Reverse-Engineering? Ich denke, es tut, und als solche möglicherweise illegal.
  2. Wird brechen, wenn GUID Form ändert.

Auch kühlere Lösung wäre ein Verfahren zum dynamischen Instrumente, durch das Ersetzen „wirft neue“ on the fly.

ich für die GuidTryParse Link stimmen von Jon oder einer ähnlichen Lösung (IsProbablyGuid). Ich werde ein wie diejenigen für meine Conversion-Bibliothek schreiben.

Ich denke, es ist total lahm ist, dass diese Frage so kompliziert sein muss. Das „ist“ oder „als“ Keyword wäre nur gut, wenn ein Guid null sein könnte. Aber aus irgendeinem Grunde, obwohl SQL Server ist mit dem OKAY, ist .NET nicht. Warum? Was ist der Wert von Guid.Empty? Dies ist nur ein dummes Problem, das durch die Gestaltung von .NET erstellt, und es ist wirklich nervt mich, wenn die Konventionen einer Sprache Schritt auf sich. Die beste Ergebnis erzielt Antwort ist bisher COM-Interop verwenden, da die Rahmen es ordnungsgemäß nicht umgehen? „Kann diese Zeichenfolge eine GUID sein?“ sein sollte, eine Frage, die leicht zu beantworten ist.

auf der Ausnahme Unter Berufung geworfen ist in Ordnung, bis die App im Internet geht. An diesem Punkt Ich habe mich nur für eine Denial-of-Service-Attacke auf. Auch wenn ich nicht „angegriffen“ bekommen, weiß ich einige Yahoo mit der URL zu Affen, oder vielleicht wird meine Marketing-Abteilung ein ungültiges Link schicken, und dann hat meine Anwendung eine ziemlich kräftigen Leistungseinbußen leiden, die bringen könnten der Server, weil ich habe meinen Code nicht schreiben, ein Problem zu behandeln, die sollte nicht passieren, aber wir alle wissen, werden passieren.

Dies verwischt die Linie ein wenig auf „Exception“ - aber unter dem Strich, auch wenn das Problem selten ist, wenn es oft genug in einer kurzen Zeitspanne passieren kann, die Ihre Anwendung abstürzt daraus die Fänge der Wartung alle, dann denke ich, werfen eine Ausnahme ist schlechte Form.

TheRage3K

Wenn TypeOf ctype (myvar, Object) Ist Guid dann .....

Private Function IsGuidWithOptionalBraces(ByRef strValue As String) As Boolean
    If String.IsNullOrEmpty(strValue) Then
        Return False
    End If

    Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^[\{]?[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}[\}]?$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function


Private Function IsGuidWithoutBraces(ByRef strValue As String) As Boolean
    If String.IsNullOrEmpty(strValue) Then
        Return False
    End If

    Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^[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}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function


Private Function IsGuidWithBraces(ByRef strValue As String) As Boolean
    If String.IsNullOrEmpty(strValue) Then
        Return False
    End If

    Return System.Text.RegularExpressions.Regex.IsMatch(strValue, "^\{[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}\}$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
End Function

Mit einer Erweiterungsmethode in C #

public static bool IsGUID(this string text)
{
    return Guid.TryParse(text, out Guid guid);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top