179 votos

C #: Prueba si la cadena es un guid sin lanzar excepciones?

Quiero tratar de convertir una cadena a un Guid, pero no quiero depender de captura de excepciones (

  • por motivos de rendimiento - las excepciones son caros
  • por razones de usabilidad - el depurador aparece
  • por razones de diseño - la espera no es excepcional

En otras palabras, el código:

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

no es adecuado.

Me gustaría probar el uso de expresiones regulares (RegEx, pero desde el guid se puede paréntesis envuelto, brace envuelto, no envueltos, hace difícil.

Además, pensé que ciertos valores Guid no son válidos(?)


Actualización 1

ChristianK tenía una buena idea para coger sólo FormatException, en lugar de todos. Cambia la pregunta del ejemplo de código para incluir sugerencia.


Actualización 2

¿Por qué preocuparse lanzado excepciones? Estoy realmente esperando no válido Guid todos los que a menudo?

La respuesta es . Es por eso que estoy usando TryStrToGuid - yo estoy esperando los malos datos.

Ejemplo 1 extensiones de espacio de Nombres puede ser especificado por anexando un GUID para el nombre de una carpeta. Yo podría ser el análisis de los nombres de carpeta, para comprobar si el texto después de la final . es un 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

Ejemplo 2 yo podría estar corriendo un muy utilizado en el servidor web quiere comprobar la validez de algunas de publicar los datos. No quiero datos no válidos atar los recursos de 2-3 órdenes de magnitud mayor de lo que necesita ser.

Ejemplo 3 podría ser el análisis de una expresión de búsqueda introducida por el usuario.

enter image description here

Si entran GUID quiero darles trámite especial (tales como, específicamente, de la búsqueda de ese objeto, o de relieve y el formato en que se concreta el término de búsqueda en el texto de respuesta.)


Actualización 3 - puntos de referencia de Rendimiento

La prueba de la conversión de 10.000 buena Guid, y 10.000 mal 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

p.s. Yo no tengo por qué justificar una pregunta.

107voto

Ian Boyd Puntos 50743

Puntos de referencia de rendimiento

 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 (la más rápida) Respuesta:

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


En pocas palabras: Si es necesario comprobar si una cadena es un guid, y usted se preocupa por el rendimiento, utilice la interoperabilidad COM.

Si usted necesita para convertir un guid en representación de String a un Guid, uso

 new Guid(someString);
 

88voto

Una vez NET 4.0 está disponible se puede utilizar Guid.TryParse ().

66voto

AnthonyWJones Puntos 122520

No te va a gustar esto, pero lo que te hace pensar que agarrar la excepción va a ser más lento?

¿Cuántos intentos fallidos de analizar un GUID espera usted en comparación con los que tienen éxito?

Mi consejo es utilizar la función que acaba de crear y el perfil de su código. Si usted encuentra que esta función es verdaderamente un punto de acceso y luego arreglarlo, pero no antes.

39voto

zhilia Puntos 1

En NET 4.0 se puede escribir de la siguiente manera:

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

21voto

Christian.K Puntos 18883

Yo por lo menos volver a escribir como:

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

No quiere decir que no válida "GUID" en SEHException, ThreadAbortException o de otro mortal o no relacionados con la materia.

Actualización: a Partir de .NET 4.0, hay un nuevo conjunto de métodos disponibles para Guid:

Realmente, los que deben ser utilizados (aunque sólo sea por el hecho de que no son "ingenuamente" que se implementa utilizando try-catch internamente).

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X