Test czy string jest guid bez rzucania WYJĄTKÓW?

Chcę spróbować przekonwertować łańcuch znaków na Guid, ale nie chcę polegać na przechwytywaniu WYJĄTKÓW (

  • ze względu na wydajność-wyjątki są drogie
  • ze względów użyteczności-debugger wyskakuje
  • ze względów projektowych - oczekiwany nie jest wyjątkowy

Innymi słowy kod:

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

Nie nadaje się.

Spróbowałbym użyć RegEx, ale ponieważ guid może być owinięty nawiasami, nawias nawiasowy, brak zawinięty, sprawia, że jest to trudne.

Dodatkowo, myślałem, że niektóre wartości Guid są nieprawidłowe(?)


Update 1

ChristianK miał dobry pomysł, aby złapać tylko FormatException, a nie wszystkie. Zmieniono próbkę kodu pytania na sugestię.


Update 2

Po co martwić się o wyrzucone wyjątki? Czy naprawdę tak często oczekuję Inwalidów?

Odpowiedź brzmi tak . Dlatego używam TryStrToGuid-i am spodziewam się złych danych.

Przykład 1 rozszerzenia przestrzeni nazw mogą być określone przez dodanie identyfikatora GUID do nazwy folderu . Mogę analizować nazwy folderów, sprawdzając, czy tekst po ostatecznym . jest 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

Przykład 2 być może używam mocno używanego serwera internetowego, który chce sprawdzić poprawność niektórych opublikowanych danych. Nie chcę, aby nieprawidłowe dane wiązały zasoby o 2-3 rzędy wielkości wyższe niż musi be.

Przykład 3 mogę analizować wyrażenie wyszukiwania wprowadzone przez użytkownika.

Tutaj wpisz opis obrazka

Jeśli wejdą w GUID, chcę je specjalnie przetworzyć (np. specjalnie wyszukać ten obiekt lub wyróżnić i sformatować konkretny termin wyszukiwania w tekście odpowiedzi.)


Aktualizacja 3-benchmarki wydajności

Test konwersji 10 000 dobrych Guidów i 10 000 złych Guidów.
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. nie powinienem usprawiedliwiać pytanie.

Author: Ian Boyd, 2008-09-19

18 answers

Wskaźniki Wydajności

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 (najszybsza) odpowiedź:

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

Bottom line: Jeśli chcesz sprawdzić, czy ciąg znaków jest guid i zależy ci na wydajności, użyj COM Interop.

Jeśli chcesz przekonwertować identyfikator guid w reprezentacji łańcuchowej na identyfikator Guid, użyj

new Guid(someString);
 107
Author: Ian Boyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-27 17:52:00

Po udostępnieniu. NET 4.0 możesz użyć Guid.TryParse().

 88
Author: No Refunds No Returns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-30 14:26:33

Nie spodoba ci się to, ale co sprawia, że myślisz, że łapanie wyjątku będzie wolniejsze?

Ile nieudanych prób parsowania GUID oczekujesz w porównaniu z udanymi?

Radzę użyć funkcji, którą właśnie stworzyłeś i profilować swój kod. Jeśli okaże się, że ta funkcja jest naprawdę hotspotem , to napraw ją, ale nie wcześniej.

 66
Author: AnthonyWJones,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 19:41:21

W. NET 4.0 można pisać w następujący sposób:

public static bool IsValidGuid(string str)
{
    Guid guid;
    return Guid.TryParse(str, out guid);
}
 39
Author: zhilia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-13 10:41:26

Napisałbym to przynajmniej jako:

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

Nie chcesz powiedzieć "invalid GUID" na SEHException, ThreadAbortException lub innych fatalnych lub niezwiązanych z nimi rzeczy.

Update : począwszy od. NET 4.0, dostępny jest nowy zestaw metod dla Guid:

Naprawdę, powinny one być używane (choćby dlatego, że nie są" naiwnie " zaimplementowane wewnętrznie przy użyciu try-catch).

 21
Author: Christian.K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-16 05:09:15

Interop jest wolniejszy niż wyłapywanie wyjątku:

Na szczęśliwej ścieżce, z 10 000 Guidami:

Exception:    26ms
Interop:   1,201ms

Na nieszczęśliwej drodze:

Exception: 1,150ms
  Interop: 1,201ms
Jest bardziej spójny, ale i wolniejszy. Wydaje mi się, że lepiej byłoby skonfigurować debugger tak, aby działał tylko na nieobsługiwanych wyjątkach.
 13
Author: Mark Brackett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-27 17:48:29

Cóż, oto regex, którego będziesz potrzebować...

^[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}(}})$
Ale to tylko na początek. Będziesz również musiał sprawdzić, czy różne części, takie jak data/godzina, mieszczą się w dopuszczalnych zakresach. Nie mogę sobie wyobrazić, że jest to szybsze niż metoda try/catch, którą już opisałeś. Mam nadzieję, że nie otrzymujesz tak wielu nieprawidłowych identyfikatorów GUID, aby zagwarantować tego typu kontrolę!
 9
Author: pdavis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-27 11:58:26

Ze względów użyteczności-debugger wyskakuje

Jeśli wybierasz podejście try / catch, możesz dodać [System.Diagnostyka.DebuggerHidden] atrybut, aby upewnić się, że debugger nie pęka, nawet jeśli Ustawiłeś go na break na throw.

 5
Author: JMD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-27 17:54:49

Chociażjest prawdą, że używanie błędów jest droższe, większość ludzi wierzy, że większość ich GUID zostanie wygenerowana komputerowo, więc TRY-CATCH nie jest zbyt droga, ponieważ generuje tylko koszty na CATCH. Możesz to udowodnić sobie za pomocą prostego testu dwóch (użytkownik publiczny, bez hasła).

Proszę bardzo:

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;
  }
 4
Author: Josef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 20:20:10

Miałem podobną sytuację i zauważyłem, że prawie nigdy nie był nieprawidłowy ciąg 36 znaków. Bazując na tym fakcie, zmieniłem trochę Twój kod, aby uzyskać lepszą wydajność, a jednocześnie zachować prostotę.

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;
    }
}
 4
Author: JBrooks,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-07-26 19:56:40

Z tego co wiem, nie ma czegoś takiego jak Guid.Spróbuj w mscrolib. Zgodnie ze źródłem odniesienia, Typ Guid ma mega-złożony konstruktor, który sprawdza wszystkie rodzaje formatów guid i próbuje je przeanalizować. Nie ma metody pomocniczej, którą można wywołać, nawet poprzez odbicie. Myślę, że trzeba szukać 3rd party Guid parsery, lub napisać swój własny.

 2
Author: Ilya Ryzhenkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 19:48:06

Uruchom potencjalny identyfikator GUID za pomocą RegEx lub niestandardowego kodu, który sprawdza rozsądność, aby upewnić się, że strig przynajmniej wygląda jak GUID i składa się tylko z ważnych znaków (i może wydaje się pasować do ogólnego formatu). Jeśli nie przejdzie przez sanity check zwróć błąd - to prawdopodobnie usunie zdecydowaną większość nieprawidłowych ciągów.

Następnie przekonwertuj łańcuch jak powyżej, wciąż łapiąc wyjątek dla kilku nieprawidłowych łańcuchów, które przechodzą przez sanity szach.

Jon Skeet zrobił analizę dla czegoś podobnego do parsowania Ints (zanim TryParse był w frameworku): sprawdzanie, czy łańcuch znaków może być przekonwertowany na Int32

Jednak, jak AnthonyWJones wskazała, że prawdopodobnie nie powinieneś się tym martwić.

 2
Author: Michael Burr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:26:00
 bool IsProbablyGuid(string s)
    {
        int hexchars = 0;
        foreach(character c in string s)
        {
           if(IsValidHexChar(c)) 
               hexchars++;          
        }
        return hexchars==32;
    }
 1
Author: rupello,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-19 19:50:27
  • Pobierz Reflektor
  • Copy ' n 'Paste Guid' s .ctor (String)
  • zastąp każde wystąpienie " rzucaj nowe ..."z "return false".

Ctor Guida jest w zasadzie skompilowanym regexem, w ten sposób uzyskasz dokładnie to samo zachowanie bez narzutu wyjątku.

    Czy to jest inżynieria odwrotna? Myślę, że tak, i jako takie może być nielegalne.
  1. złamie się, jeśli zmieni się formularz GUID.

Jeszcze chłodniejszym rozwiązaniem byłoby dynamicznie instrument metody, zastępując "throw new" w locie.

 1
Author: THX-1138,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-27 17:59:13

Głosuję za linkiem GuidTryParse zamieszczonym powyżej przez Jon lub podobnym rozwiązaniem (IsProbablyGuid). Będę pisał takie jak te dla mojej biblioteki konwersji.

Myślę, że to beznadziejne, że to pytanie musi być tak skomplikowane. Słowo kluczowe " is " Lub " as " byłoby w porządku, gdyby identyfikator Guid mógł być null. Ale z jakiegoś powodu, nawet jeśli SQL Server jest w porządku z tym,. NET nie jest. Dlaczego? Jaka jest wartość Guid.Pusty? Jest to po prostu głupi problem stworzony przez projekt. NET, i to naprawdę denerwuje mnie, gdy konwencje języka krok na siebie. Jak do tej pory najlepszą odpowiedzią było użycie COM Interop, bo Framework nie radzi sobie z tym z gracją? "Czy ten ciąg może być GUID?"powinno być to pytanie, na które łatwo odpowiedzieć.

Opieranie się na rzucanym wyjątku jest OK, dopóki aplikacja nie przejdzie do Internetu. W tym momencie ustawiłem się na atak typu odmowa usługi. Nawet jak mnie nie "zaatakują" to Wiem, że jakiś yahoo będzie małpą z URL, a może mój dział marketingu wyśle nieprawidłowy link, a potem moja aplikacja musi cierpieć dość silny hit wydajności, który może zniszczyć serwer, ponieważ nie napisałem kodu, aby poradzić sobie z problemem, który nie powinien się zdarzyć, ale wszyscy wiemy, że się stanie.

To zaciera linię nieco na "wyjątek" - ale podsumowując, nawet jeśli problem jest rzadki, jeśli może się zdarzyć wystarczająco dużo razy w krótkim czasie, że aplikacja zawiesza się obsługując połowy z tego wszystkiego, więc myślę, że rzucanie WYJĄTKÓW to zła forma.

TheRage3K

 1
Author: 2 revsTheRage3K,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:36

If TypeOf ctype (myvar,Object) Is Guid then .....

 0
Author: mbm_tn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-23 14:20:55
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
 0
Author: Stefan Steiger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-20 11:54:44

Z metodą rozszerzenia w C #

public static bool IsGUID(this string text)
{
    return Guid.TryParse(text, out Guid guid);
}
 0
Author: Mike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-20 20:29:54