Sprawdź, czy ciąg jest guid bez rzucania wyjątków?

głosy
171

Chcę spróbować przekonwertować ciąg na GUID, ale nie chcę polegać na łapanie wyjątków (

  • ze względu na wydajność - wyjątki są drogie
  • ze względów użytkowych - debugger wyskakuje
  • ze względów konstrukcyjnych - oczekiwany nie jest wyjątkowa

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.

Chciałbym spróbować użyć wyrażenia regularnego, ale ponieważ GUID może być nawias zapakowane, owinięte klamra, żaden zapakowane, sprawia, że ​​trudno.

Dodatkowo, myślałem pewne wartości Guid są nieważne (?)


Update 1

ChristianK miał dobry pomysł, tylko złapać FormatException, a nie wszystkich. Zmieniono kod przykładowy Pytanie do zawierać sugestię.


aktualizacja 2

Dlaczego martwić rzucone wyjątki? Ja naprawdę spodziewa nieprawidłowe GUID tak często?

Odpowiedź brzmi: tak . Dlatego używam TryStrToGuid - I am spodziewa złych danych.

Przykład 1 rozszerzenia przestrzeni nazw można określić przez dodanie GUID do nazwy folderu . I może być parsowania nazwy folderów, sprawdzając, czy tekst po finale . 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 I może być uruchomiony mocno używane web-server chce sprawdzić ważność niektórych zamieszczonych powrotem danych. Nie chcę nieprawidłowe dane zajęcia zasobów 2-3 rzędy wielkości wyższe niż to musi być.

Przykład 3 mogę być analizowania ekspresji wyszukiwania wprowadzonych przez użytkownika.

wprowadzić

Jeśli wpisać one GUID Mówię chcą przetwarzać je specjalnie (jak konkretnie szukają dla tego obiektu, lub zaznacz i format, który konkretny termin wyszukiwania w tekście odpowiedzi).


Update 3 - testy wydajności

Test konwersji 10.000 GUID dobrych i złych 10.000 GUID.

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

PS I nie powinno się uzasadniać pytanie.

Utwórz 19/09/2008 o 20:35
źródło użytkownik
W innych językach...                            


18 odpowiedzi

głosy
107

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

Konkluzja: Jeśli chcesz sprawdzić, czy ciąg jest GUID, a zależy Ci na wydajności, należy użyć COM Interop.

Jeśli trzeba konwertować GUID w reprezentacji ciąg na GUID, użytkowania

new Guid(someString);
Odpowiedział 13/11/2008 o 20:00
źródło użytkownik

głosy
85

Po .net 4.0 jest dostępny można użyć Guid.TryParse().

Odpowiedział 31/12/2009 o 05:58
źródło użytkownik

głosy
66

Nie spodoba ci się to, ale co sprawia, że ​​myślisz, że łowienie wyjątek będzie wolniej?

Ile nieudanych prób analizowania GUID oczekujesz w stosunku do udanych?

Radzę skorzystać z właśnie utworzoną funkcję i profil kodu. Jeśli okaże się, że ta funkcja jest naprawdę hotspot następnie go naprawić, ale nie wcześniej.

Odpowiedział 19/09/2008 o 20:41
źródło użytkownik

głosy
39

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

public static bool IsValidGuid(string str)
{
    Guid guid;
    return Guid.TryParse(str, out guid);
}
Odpowiedział 30/06/2011 o 11:18
źródło użytkownik

głosy
20

Chciałbym przynajmniej przepisać jako:

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

Nie chcesz powiedzieć „nieprawidłowy identyfikator GUID” na SEHException, ThreadAbortException lub innego śmiertelnego lub nie powiązanych rzeczy.

Aktualizacja : Począwszy od .NET 4.0, pojawił się nowy zestaw metod dostępnych dla GUID:

Naprawdę, te powinny być stosowane (choćby na fakt, że nie są one „naiwnie” realizowane za pomocą try-catch wewnętrznie).

Odpowiedział 26/09/2008 o 05:49
źródło użytkownik

głosy
13

Współdziałanie jest wolniejsze niż po prostu połowu wyjątek:

W szczęśliwej drogi, z 10.000 GUID:

Exception:    26ms
Interop:   1,201ms

W nieszczęśliwym ścieżce:

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

To jest bardziej spójna, ale również konsekwentnie wolniejsze. Wydaje mi się, że będziesz lepiej konfiguracji debuggera tylko przerwa na nieobsłużonych wyjątków.

Odpowiedział 14/11/2008 o 18:02
źródło użytkownik

głosy
9

Cóż, tutaj jest regex trzeba będzie ...

^[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. Trzeba będzie również sprawdzenie, czy poszczególne elementy takie jak data / czas mieszczą się w dopuszczalnych granicach. Nie mogę sobie wyobrazić, co jest szybciej niż metoda try / catch, że już opisanej. Mam nadzieję, że nie otrzymują, że wiele nieprawidłowych GUID, aby uzasadnić tego rodzaju czeku!

Odpowiedział 19/09/2008 o 20:46
źródło użytkownik

głosy
5

ze względów użytkowych - debugger wyskakuje

Jeśli idziesz na podejście try / catch można dodać [System.Diagnostics.DebuggerHidden] przypisują upewnić debugger nie pęka nawet jeśli ustawić go złamać na rzut.

Odpowiedział 27/05/2009 o 18:54
źródło użytkownik

głosy
4

Chociaż jest prawdą, że przy użyciu błędów jest droższe, większość ludzi uważa, że większość ich GUID będą generowane komputerowo więc TRY-CATCHnie jest zbyt kosztowne, ponieważ tylko generuje koszty na CATCH. Można to udowodnić sobie z prostym teście dwóch (publiczny użytkownika, hasło nie).

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;
  }
Odpowiedział 19/09/2008 o 20:52
źródło użytkownik

głosy
3

Miałem podobną sytuację i zauważyłem, że prawie nigdy nie był nieprawidłowy ciąg długości 36 znaków. Tak więc na podstawie tego faktu, zmieniłem swój kod trochę uzyskać lepszą wydajność przy jednoczesnym zachowaniu prostoty.

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;
    }
}
Odpowiedział 26/07/2009 o 20:56
źródło użytkownik

głosy
2

O ile mi wiadomo, nie ma coś takiego jak Guid.TryParse w mscrolib. Według Źródła Referencyjnego, typ Guid ma mega-kompleks konstruktora, który sprawdza wszystkie rodzaje formatów GUID i stara się je analizować. Nie ma metody pomocnika można zadzwonić, nawet poprzez refleksję. Myślę, że trzeba szukać 3rd party GUID parserami lub napisać własne.

Odpowiedział 19/09/2008 o 20:48
źródło użytkownik

głosy
2

Uruchomić potencjał GUID chociaż regex lub jakiś niestandardowy kod, który robi testow w celu zapewnienia strig przynajmniej wygląda jak GUID i składa się tylko z ważnych znaków (i być może, że wydaje się pasować do ogólnego wzoru). Jeśli to nie przejdzie sprawdzenia dokonywane zwróci błąd - że pewnie wyeliminować większość nieprawidłowych ciągów.

Następnie przekonwertować ciąg, jak masz powyżej, nadal połowu wyjątek dla kilku nieprawidłowych ciągów uzyskać poprzez kontrola poprawności.

Jon Skeet zrobił analizę czegoś podobnego do parsowania INTS (przed TryParse była w ram): Sprawdzanie, czy ciąg znaków może być przekształcany do Int32

Jednak, jak AnthonyWJones wskazany was zapewne nie należy się tym martwić.

Odpowiedział 19/09/2008 o 20:41
źródło użytkownik

głosy
1

Głosuję za link GuidTryParse zamieszczonych powyżej przez Jona lub podobnego rozwiązania (IsProbablyGuid). Będę pisać jedną jak te dla mojej bibliotece konwersji.

Myślę, że jest całkowicie lame, że kwestia ta musi być tak skomplikowane. W „jest” lub „jako” słowo kluczowe byłoby po prostu w porządku, jeśli GUID może być zerowa. Ale z jakiegoś powodu, mimo że SQL Server jest OK z tym, .NET nie jest. Czemu? Jaka jest wartość Guid.Empty? To jest po prostu głupie problemem stworzony przez projekcie .NET, a tak naprawdę robaki mnie o konwencje kroku językowej na sobie. Najlepiej wykonując odpowiedź dotąd za pomocą COM Interop ponieważ Framework nie obsługuje go bezpiecznie? „Może to być ciąg GUID?” powinno być wątpliwości, że jest łatwo odpowiedzieć.

Powołując się na wyjątek jest rzucony jest OK, aż aplikacja przechodzi w internecie. W tym momencie po prostu ustawić się w górę na atak Denial of Service. Nawet jeśli nie dostanę „zaatakowany”, wiem, że niektórzy Yahoo zamierza małpa z adresem URL, czy może mój dział marketingu wyśle ​​nieprawidłowy łącze, a następnie moja aplikacja musi cierpieć dość mocny spadek wydajności, który może przynieść w dół serwera bo nie napisać kod, aby obsłużyć problem, że nie powinno się zdarzyć, ale wszyscy wiemy, nie nastąpi.

To zaciera granicę trochę na „wyjątek” - ale zyski, nawet jeśli problem jest rzadko, jeśli może się zdarzyć, tyle razy w krótkim przedziale czasu, że awarie aplikacji obsługujących połowów od tego wszystkiego, to myślę, że rzuca wyjątek jest zła forma.

TheRage3K

Odpowiedział 23/08/2009 o 00:21
źródło użytkownik

głosy
1
  • Uzyskaj reflektor
  • copy'n'paste .ctor GUID za (String)
  • zastąpić każde wystąpienie „rzucać nowe ...” z „return false”.

konstruktor GUID jest dość dużo skompilowane regex, że sposób dostaniesz dokładnie to samo zachowanie, bez obciążania wyjątku.

  1. Będzie to stanowić reverse engineering? Myślę, że to robi, i jako taki może być nielegalne.
  2. Złamie jeśli zmiany formy GUID.

Nawet chłodnica rozwiązaniem byłoby dynamicznie instrumentem metodę, zastępując „rzucać nowe” w locie.

Odpowiedział 27/05/2009 o 18:59
źródło użytkownik

głosy
1
 bool IsProbablyGuid(string s)
    {
        int hexchars = 0;
        foreach(character c in string s)
        {
           if(IsValidHexChar(c)) 
               hexchars++;          
        }
        return hexchars==32;
    }
Odpowiedział 19/09/2008 o 20:50
źródło użytkownik

głosy
0

Z metodę rozszerzenia w C #

public static bool IsGUID(this string text)
{
    return Guid.TryParse(text, out Guid guid);
}
Odpowiedział 20/07/2017 o 20:29
źródło użytkownik

głosy
0
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
Odpowiedział 20/08/2009 o 12:54
źródło użytkownik

głosy
0

jeśli typeof ctype (myVar, Object) to Guid potem .....

Odpowiedział 23/05/2009 o 15:20
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more