Quiero intentar convertir una cadena en un Guid, pero no quiero confiar en la captura de excepciones (
- por motivos de rendimiento: las excepciones son caras
- por razones de usabilidad: aparece el depurador
- por razones de diseño: lo esperado 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.
Intentaría usar RegEx, pero dado que el guid puede estar entre paréntesis, entre paréntesis, ninguno, lo hace difícil.
Además, pensé que ciertos valores Guid no son válidos (?)
Actualización 1
ChristianK tuvo una buena idea para atrapar solo FormatException
, en lugar de todos. Se modificó el ejemplo de código de la pregunta para incluir una sugerencia.
Actualización 2
¿Por qué preocuparse por las excepciones lanzadas? ¿Realmente espero GUID inválidos con tanta frecuencia?
La respuesta es si . Es por eso que estoy usando TryStrToGuid - Yo estoy esperando los datos erróneos.
Ejemplo 1 Las extensiones de espacio de nombres se pueden especificar agregando un GUID al nombre de una carpeta . Podría estar analizando los nombres de las carpetas, comprobando si el texto aparece 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 Podría estar ejecutando un servidor web muy usado que quiere verificar la validez de algunos datos devueltos. No quiero datos no válidos que agrupen recursos de 2 a 3 órdenes de magnitud más de lo necesario.
Ejemplo 3 Podría estar analizando una expresión de búsqueda ingresada por un usuario.
Si ingresan los GUID, quiero procesarlos especialmente (como buscar específicamente ese objeto, o resaltar y formatear ese término de búsqueda específico en el texto de respuesta).
Actualización 3 - Puntos de referencia de rendimiento
Pruebe convertir 10,000 Guías buenas y 10,000 Guías malas.
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
PD: No debería tener que justificar una pregunta.
4.0
. Es por eso que la pregunta y la respuesta aceptada son como son.Respuestas:
Benchmarks de rendimiento
Respuesta intertop COM (más rápida):
En pocas palabras: si necesita verificar si una cadena es un guid y le preocupa el rendimiento, use COM Interop.
Si necesita convertir un guid en representación de cadena en un Guid, use
fuente
Una vez que .net 4.0 esté disponible, puede usarlo
Guid.TryParse()
.fuente
No te va a gustar esto, pero ¿qué te hace pensar que atrapar la excepción va a ser más lento?
¿Cuántos intentos fallidos de analizar un GUID espera en comparación con los exitosos?
Mi consejo es usar la función que acaba de crear y perfilar su código. Si encuentra que esta función es realmente un punto de acceso, entonces corríjala, pero no antes.
fuente
En .NET 4.0 puede escribir de la siguiente manera:
fuente
Al menos lo reescribiría como:
No desea decir "GUID inválido" en SEHException, ThreadAbortException u otras cosas fatales o no relacionadas.
Actualización : a partir de .NET 4.0, hay un nuevo conjunto de métodos disponibles para Guid:
Guid.TryParse
Guid.TryParseExact
En realidad, deberían usarse (aunque solo sea por el hecho de que no se implementan "ingenuamente" usando try-catch internamente).
fuente
La interoperabilidad es más lenta que solo detectar la excepción:
En el camino feliz, con 10,000 Guías:
En el camino infeliz:
Es más consistente, pero también es consistentemente más lento. Me parece que sería mejor configurar su depurador para que solo rompa las excepciones no controladas.
fuente
Bueno, aquí está la expresión regular que necesitará ...
Pero eso es solo para empezar. También deberá verificar que las distintas partes, como la fecha / hora, se encuentren dentro de los rangos aceptables. No puedo imaginar que esto sea más rápido que el método try / catch que ya ha descrito. ¡Esperemos que no esté recibiendo tantos GUID inválidos para garantizar este tipo de verificación!
fuente
Si va por el enfoque de prueba / captura, puede agregar el atributo [System.Diagnostics.DebuggerHidden] para asegurarse de que el depurador no se rompa incluso si lo ha configurado para que se rompa en el lanzamiento.
fuente
Si bien es cierto que el uso de errores es más costoso, la mayoría de las personas creen que la mayoría de sus GUID serán generados por computadora, por
TRY-CATCH
lo que no es demasiado costoso ya que solo genera costos en elCATCH
. Puede probarlo usted mismo con una simple prueba de los dos (usuario público, sin contraseña).Aqui tienes:
fuente
Tuve una situación similar y noté que casi nunca la cadena inválida tenía 36 caracteres. Entonces, en base a este hecho, cambié un poco su código para obtener un mejor rendimiento sin dejar de ser simple.
fuente
Que yo sepa, no hay nada como Guid. TryParse en mscrolib. Según Reference Source, el tipo Guid tiene un constructor megacomplejo que verifica todo tipo de formatos guid e intenta analizarlos. No hay un método auxiliar al que pueda llamar, incluso a través de la reflexión. Creo que tienes que buscar analizadores Guid de terceros o escribir el tuyo propio.
fuente
Ejecute el GUID potencial a través de un RegEx o algún código personalizado que haga una comprobación de sanidad para garantizar que el strig al menos se parezca a un GUID y consista solo en caracteres válidos (y tal vez parece que se ajusta al formato general). Si no pasa la verificación de cordura, se devuelve un error, eso probablemente eliminará la gran mayoría de las cadenas no válidas.
Luego, convierta la cadena como lo hizo anteriormente, aún capturando la excepción para las pocas cadenas no válidas que pasan por la comprobación de cordura.
Jon Skeet hizo un análisis de algo similar para analizar Ints (antes de que TryParse estuviera en el Framework): Verificar si una cadena se puede convertir a Int32
Sin embargo, como AnthonyWJones indicó, probablemente no deberías preocuparte por esto.
fuente
fuente
Guid's ctor es más o menos una expresión regular compilada, de esa manera obtendrá exactamente el mismo comportamiento sin sobrecarga de la excepción.
Una solución aún mejor sería instrumentar dinámicamente un método, al reemplazar "lanzar nuevo" sobre la marcha.
fuente
Voto por el enlace Guid TryParse publicado anteriormente por Jon o una solución similar (IsProbablyGuid). Escribiré uno como esos para mi biblioteca de conversión.
Creo que es totalmente lamentable que esta pregunta tenga que ser tan complicada. La palabra clave "es" o "como" estaría bien SI un Guid pudiera ser nulo. Pero por alguna razón, aunque SQL Server está bien con eso, .NET no lo está. ¿Por qué? ¿Cuál es el valor de Guid.Empty? Este es solo un problema tonto creado por el diseño de .NET, y realmente me molesta cuando las convenciones de un lenguaje se interponen en sí mismas. ¿La respuesta de mejor desempeño hasta ahora ha sido usar COM Interop porque el Framework no lo maneja con gracia? "¿Puede esta cadena ser un GUID?" debe ser una pregunta fácil de responder.
Confiar en la excepción lanzada está bien, hasta que la aplicación se conecte a Internet. En ese momento, me preparé para un ataque de denegación de servicio. Incluso si no me "atacan", sé que algunos ya se irán con la URL, o tal vez mi departamento de marketing enviará un enlace con formato incorrecto, y luego mi aplicación tendrá que sufrir un impacto de rendimiento bastante considerable que PODRÍA traer fuera del servidor porque no escribí mi código para manejar un problema que NO DEBERÍA suceder, pero todos sabemos que PASARÁ.
Esto desdibuja un poco la línea en "Excepción", pero el resultado final, incluso si el problema es infrecuente, si puede suceder suficientes veces en un corto período de tiempo que su aplicación se bloquea al atender las capturas de todo, entonces creo que lanzar una excepción es mala forma.
TheRage3K
fuente
si TypeOf ctype (myvar, Object) es Guid entonces .....
fuente
fuente
Con un método de extensión en C #
fuente