2010-12-30 9 views
17

Este ejemplo está en C# pero espero que pueda aplicarse a otros con la misma facilidad.¿Algún problema al declarar una variable y usar TryParse para inicializarla en la misma línea?

Recientemente he descubierto que la siguiente parece funcionar muy bien:

int i = Int32.TryParse(SomeString, out i) ? i : -1; 

De alguna manera, parece como si la variable i no debería ser técnicamente accesibles en el punto que aparece en TryParse. ¿O sería correcto suponer que int i declara efectivamente la variable, a pesar de que todavía no hay un final de declaración?

+0

¡Ja!Eso es tan cool. Este código no es bueno si -1 es un valor válido de SomeString, pero aún así. A menudo me gustaría poder declarar una variable de "salida" implícitamente, p. ¿No sería bueno si pudieras escribir 'if (int.TryParse (s, out var i)) {...}' donde 'i' es una nueva variable que nunca se declaró previamente? – Qwertie

+0

Tal vez, como sugiere Henk, un método de ayuda es lo mejor. por ejemplo, 'int CustomIntParse (string s, int default) {}' – JYelton

+0

He tomado una foto de algunos métodos de ayuda a considerar. –

Respuesta

10

int i declara la variable, y usándola en el parámetro out la inicializa. Dado que el predicado debe evaluarse antes que el consecuente, i es tanto declarado como inicializado antes de su uso. (out parámetros deben ser asignados antes de regresar, por lo que definitivamente se inicializa en cualquier caso.)

Dicho esto, hay colegas míos que se verían afectados al ver algo así por motivos de estilo. :-)

EDIT: Después de estudiar cómo se ha agotado esto, propondré un par de posibles métodos alternativos de ayuda. La denominación de la clase estática actúa aquí como documentación de intención para los métodos auxiliares.

internal static class TryConvert 
{ 
    /// <summary> 
    /// Returns the integer result of parsing a string, or null. 
    /// </summary> 
    internal static int? ToNullableInt32(string toParse) 
    { 
     int result; 
     if (Int32.TryParse(toParse, out result)) return result; 
     return null; 
    } 

    /// <summary> 
    /// Returns the integer result of parsing a string, 
    /// or the supplied failure value if the parse fails. 
    /// </summary> 
    internal static int ToInt32(string toParse, int toReturnOnFailure) 
    { 
     // The nullable-result method sets up for a coalesce operator. 
     return ToNullableInt32(toParse) ?? toReturnOnFailure; 
    } 
} 

internal static class CallingCode 
{ 
    internal static void Example(string someString) 
    { 
     // Name your poison. :-) 
     int i = TryConvert.ToInt32(someString, -1); 
     int j = TryConvert.ToNullableInt32(someString) ?? -1; 

     // This avoids the issue of a sentinel value. 
     int? k = TryConvert.ToNullableInt32(someString); 
     if (k.HasValue) 
     { 
      // do something 
     } 
    } 
} 
+0

Es por eso que planteo la pregunta. Siempre busco simplificar el código (al menos hasta el punto en que sea legible). Siento que esta afirmación es legible, pero ¿podría profundizar en las consideraciones de estilo? – JYelton

+0

@JYelton Algunas personas encuentran que los operadores ternarios son menos legibles para los principiantes. Luego está el hecho de que existe el uso del efecto secundario del parámetro out para inicializar i antes de la asignación de la rama ternaria. Si tiene que hacer una pregunta sobre SO, si hay algún problema al hacer esto, ha respondido su pregunta de legibilidad. :) –

+0

Soy uno de esos que darían un ataque por motivos de estilo. Mientras que funciona, parece confuso. No es inmediatamente obvio lo que está pasando, así que tengo que jugar compilador para resolverlo. –

4

Recientemente he descubierto que la siguiente parece funcionar muy bien

int i = Int32.TryParse(SomeString, out i) ? i : -1; 

Funciona, pero no está muy bien.

¿Algún problema al declarar una variable y usar TryParse para inicializarla en la misma línea?

Sí, legibilidad. Creo que esto se ve horrible, y está haciendo un doble trabajo.


Parte del problema es que desea -1 como predeterminado. Int32.TryParse define explícitamente 0 como el valor de salida cuando falla la conversión.

Aún así lo dividiría en 2 líneas por motivos de legibilidad.

int i; 
if (! int.TryParse(SomeString, out i)) i = -1; 

Y cuando se necesita mucho esto, escribir un método de ayuda (extensión estática pero no):

int i = Utils.ParseInt(SomeString, -1); 
+0

¿Podría simplemente dividir esto en líneas de código separadas? ¿O hay otra forma concisa de establecer un int para un valor analizado de una cadena y especificar un valor predeterminado para la falla de análisis sintáctico? – JYelton

+0

JYelton: pregunta justa, TryParse es feo. Voy a editar –

+0

Me gusta el método estático de ayuda. Hace obvio lo que está sucediendo. –

4

Recuerde que no hay ningún operador ternario en CIL.

int i = Int32.TryParse(SomeString, out i) ? i : -1; 

Su código se transforma en CIL que representa el siguiente código C#:

int i; 
if (Int32.TryParse(SomeString, out i)) 
    i = i; 
else 
    i = -1; 

que está perfectamente bien.

+0

Esto deja más claro que si insistía en mantener esta estructura, al menos debería invertir la declaración if para que 'i' solo se configure en caso de falla (que se muestra en el ejemplo de Henk). Gracias. – JYelton

Cuestiones relacionadas