Проверьте, является ли строка идентификатором guid без исключения?



Я хочу попробовать преобразовать строку в Guid, но я не хочу полагаться на ловить исключения (




  • по соображениям производительности-исключения стоят дорого

  • по соображениям удобства использования-отладчик всплывает

  • по причинам дизайна-ожидаемое не является исключительным


другими словами код:



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


не подходит.



Я бы попробовал использовать регулярное выражение, но так как guid может быть заключен в скобки, бандаж завернутый, ни один не завернутый, делает его жестким.



кроме того, я думал, что некоторые значения Guid недопустимы(?)





обновление 1



у Кристиана была хорошая идея поймать только FormatException, а не все. Изменен пример кода вопроса, чтобы включить предложение.





обновление 2



зачем беспокоиться о исключений? Я действительно ожидаю, что недействительные GUID так часто?



в ответ:да. Вот почему я использую TryStrToGuid-I am ожидают плохих данных.



Пример 1расширения пространства имен может быть определено путем добавления идентификатора GUID в имени папки. Возможно, я разбираю имена папок, проверяя, есть ли текст после окончательного . является 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


Пример 2 возможно, я запускаю сильно используемый веб-сервер, который хочет проверить действительность некоторых отправил данные. Я не хочу, чтобы неверные данные связывали ресурсы на 2-3 порядка выше, чем это должно быть.



Пример 3 возможно, я анализирую выражение поиска, введенное пользователем.



enter image description here



если они вводят GUID, я хочу обработать их специально (например, специально искать этот объект или выделять и форматировать этот конкретный поисковый запрос в тексте ответа.)





Обновление 3 - Производительность контрольные показатели

1020   18  

18 ответов:

Тесты Производительности

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 (самый быстрый) ответ:

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

итог: Если вам нужно проверить, является ли строка идентификатором guid, и вы заботитесь о производительности, используйте com-взаимодействие.

Если вам нужно преобразовать guid в строковое представление в Guid, используйте

new Guid(someString);

после того, как .net 4.0 доступен вы можете использовать Guid.TryParse().

вам это не понравится, но что заставляет вас думать, что поймать исключение будет медленнее?

сколько неудачных попыток разбора GUID вы ожидаете по сравнению с успешными?

мой совет-используйте функцию, которую вы только что создали, и профилируйте свой код. Если вы обнаружите, что эта функция действительно является точка затем исправить это, но не раньше.

в .NET 4.0 вы можете написать следующее:

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

Я бы по крайней мере переписал его как:

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

вы не хотите говорить "недопустимый GUID" на SEHException, ThreadAbortException или других фатальных или не связанных с ними вещей.

обновление: начиная с .NET 4.0, существует новый набор методов, доступных для Guid:

действительно, те, которые должны быть использованы (хотя бы для того, что они не являются "наивно" реализовано с помощью try-catch внутренне).

взаимодействие происходит медленнее, чем просто поймать исключение:

в счастливом пути, с 10 000 Guids:

Exception:    26ms
Interop:   1,201ms

в несчастном пути:

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

это более последовательно, но это также последовательно медленнее. Мне кажется, вам было бы лучше настроить свой отладчик только на необработанные исключения.

Ну, вот регулярное выражение, которое вам понадобится...

^[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}(}})$

но это только для начала. Вам также придется проверить, что различные части, такие как дата/время, находятся в допустимых диапазонах. Я не могу представить, что это будет быстрее, чем метод try/catch, который вы уже описали. Надеюсь, вы не получаете столько недействительных GUID, чтобы гарантировать этот тип проверки!

по соображениям удобства использования-отладчик всплывает

Если вы собираетесь использовать подход try/catch, вы можете добавить [System.Диагностика.DebuggerHidden] атрибут, чтобы убедиться, что отладчик не ломается, даже если вы установили его на разрыв при броске.

а то и правда, что использование ошибок дороже, большинство людей считают, что большинство их GUID будут сгенерированы компьютером, поэтому TRY-CATCH не слишком дорого, так как он генерирует только стоимость на CATCH. Вы можете доказать это себе с помощью простого теста два (публичное пользователя, без пароля).

вот так:

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

У меня была похожая ситуация и я заметил, что почти никогда не была недопустимая строка 36 символов. Поэтому, основываясь на этом факте, я немного изменил ваш код, чтобы получить лучшую производительность, сохраняя его простым.

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

насколько я знаю, Нет ничего похожего на Guid.TryParse в mscrolib. Согласно справочному источнику, тип Guid имеет мега-сложный конструктор, который проверяет все виды форматов guid и пытается их разобрать. Нет никакого вспомогательного метода, который вы можете вызвать, даже через отражение. Я думаю, что вам нужно искать сторонние Парсеры Guid или писать свои собственные.

запустите потенциальный идентификатор GUID, хотя регулярное выражение или некоторый пользовательский код, который выполняет проверку здравомыслия, чтобы убедиться, что strig по крайней мере выглядит как идентификатор GUID и состоит только из допустимых символов (и, возможно, что он соответствует общему формату). Если он не пройдет проверку здравомыслия, верните ошибку - это, вероятно, отсеет подавляющее большинство недействительных строк.

затем преобразуйте строку, как у вас есть выше, все еще ловя исключение для нескольких недопустимых строк, которые проходят через здравомыслие проверять.

Джон Скит сделал анализ для чего-то подобного для разбора Ints (до того, как TryParse был в рамках): проверка если строка может быть преобразована в int32

, а AnthonyWJones указал, что вы, вероятно, не должны беспокоиться об этом.
 bool IsProbablyGuid(string s)
    {
        int hexchars = 0;
        foreach(character c in string s)
        {
           if(IsValidHexChar(c)) 
               hexchars++;          
        }
        return hexchars==32;
    }
  • Сделать Отражатель
  • копировать-Н-'paste идентификатор GUID .конструктор(строка)
  • замените каждое появление "бросить новый ..."с "return false".

ctor Guid-это в значительной степени скомпилированное регулярное выражение, таким образом, вы получите точно такое же поведение без накладных расходов исключения.

  1. означает ли это обратное проектирование? Я думаю, что это так, и как таковой может быть незаконным.
  2. сломается, если форма GUID изменения.

еще более крутым решением было бы динамически измерять метод, заменяя "бросок нового" на лету.

Я голосую за ссылку GuidTryParse, опубликованную выше Йон или аналогичное решение (IsProbablyGuid). Я буду писать один, как те, для моей библиотеки преобразования.

Я думаю, что это безнадежно, что этот вопрос должен быть настолько сложным. Ключевое слово" is "или" as " было бы просто отлично, если бы Guid мог быть null. Но по какой-то причине, даже если SQL Server в порядке с этим, .NET-нет. Зачем? Каково значение Guid.Пусто? Это просто глупая проблема, созданная дизайн .NET, и это действительно меня раздражает, когда соглашения языка наступают на себя. Наиболее эффективным ответом до сих пор было использование com-взаимодействия, потому что фреймворк не обрабатывает его изящно? "Может ли эта строка быть GUID?"должен быть вопрос, на который легко ответить.

полагаясь на исключение выбрасывается нормально, пока приложение не выходит в интернет. В этот момент я просто настроил себя на атаку отказа в обслуживании. Даже если меня не "атакуют", я знаю, что некоторые yahoo переход к обезьяне с URL-адресом, или, может быть, мой отдел маркетинга отправит искаженную ссылку, а затем мое приложение должно пострадать от довольно сильного удара производительности, который может сбить сервер, потому что я не написал свой код для обработки проблемы, которая не должна произойти, но мы все знаем, что произойдет.

это размывает строку немного на "исключение" - но итог, даже если проблема нечастая, если это может произойти достаточно раз за короткий промежуток времени, что ваше приложение аварийно завершает работу обслуживание уловов от всего этого, то я думаю, что бросать исключение-это плохой тон.

TheRage3K

Если ctype для вызова typeof(аргумент myVar,объект) - это идентификатор GUID, затем .....

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

С методом расширения в C#

public static bool IsGUID(this string text)
{
    return Guid.TryParse(text, out Guid guid);
}

Comments

    Ничего не найдено.