martes, 5 de mayo de 2015
Compartir:

String.Format()
para construir strings más complejos. Hace unos meses ya adelantamos por aquí sus principales características, aunque aún era algo pronto para poder probar en profundidad esta nueva y esperada feature. Ahora, más avanzado ya su desarrollo, ha llegado el momento de echarle otro vistazo más en profundidad y ver cómo queda finalmente (o casi finalmente, todavía podría cambiar algo!).
En este post vamos a ver rápidamente los puntos principales a tener en cuenta para dominar esta nueva característica que sin duda facilitará nuestro trabajo y nos hará más productivos.
1. Interpolación de cadenas a vista de pájaro
Consiste en introducir valores de variables o expresiones en el interior de cadenas de texto sin usar los tradicionales mecanismos, molestos y propensos a errores, como la concatenación o el formateo conString.Format()
. Y como un poco de código vale más que mil palabras, he ahí un ejemplo que creo ilustra bastante bien de qué estamos hablando:

Las cadenas interpoladas comienzan con el prefijo “$”, y pueden aparecer en los mismos lugares que una cadena de caracteres tradicional. Es decir, donde siempre hemos podido introducir una cadena de texto, podremos introducir ahora la nueva construcción
$"something"
. 2. Parámetros en cadenas interpoladas
Cuando el compilador de C# encuentra una cadena precedida por el símbolo “$” entenderá que es una cadena con interpolación, y creará el string resultante sustituyendo las expresiones contenidas entre llaves por su valor evaluado en el ámbito local.Por ejemplo, en la siguiente porción de código se muestra el uso correcto de la variable local
name
y de la propiedad estática LastName
, mientras que la propiedad age
no puede referenciarse desde el método estático Main()
por ser un miembro de instancia: 
Si queremos introducir los caracteres de apertura o cierre de llaves en alguna de estas cadenas, debemos escaparlos introduciéndolos dos veces consecutivas:

3. Intellisense, refactorings y errores en compilación
Visual Studio nos ayudará durante la codificación de estas cadenas gracias al soporte completo de intellisense en el interior de las expresiones interpoladas:
También estos parámetros en el interior de las cadenas de texto serán sensibles a refactorizaciones. Por ejemplo, si en el código anterior renombramos la variable
name
a fullName
, el nuevo nombre será introducido también automáticamente en el interior de la cadena: 
Y por supuesto, cualquier error a la hora de codificar las expresiones se nos notificará en tiempo de compilación, evitando así problemas posteriores, e incluso Visual Studio nos propondrá posibles soluciones para corregirlo:

4. Expresiones como parámetros
Aunque la forma habitual de uso será probablemente utilizar directamente variables o propiedades como parámetros en las cadenas interpoladas, en realidad entre la apertura y cierre de las llaves podemos poner cualquier expresión que evalúe aobject
. En la práctica, cualquier expresión no void
valdrá: 
Por supuesto, podemos incluir todo tipo de expresiones, aunque a veces será necesario el uso de paréntesis:

La única condición es que la expresión sea válida y compilable en el punto exacto en el que se produce la interpolación. Si la expresión contiene términos definidos en espacios de nombre distintos al actual, o bien se cualifican por completo o bien se insertan los
using
necesarios en el archivo de código fuente en el que se encuentra la expresión. 5. Los parámetros pueden ser formateados
Al igual que ocurre en el clásicoString.Format()
, podemos incluir información de formato en los parámetros que incluimos en las cadenas interpoladas con una sintaxis bastante predecible: simplemente, tras la expresión a evaluar, incluimos el carácter dos puntos “:” y a continuación la cadena de formato que especifica cómo debe presentarse la información. Las cadenas de formato son las estándar en .NET, las que hemos usado toda la vida en
String.Format()
. Veamos unos ejemplos: 
Opcionalmente podemos indicar también el número de caracteres del resultado insertando antes de la especificación el número separado por una coma, y la alineación del contenido (derecha positivo, izquierda negativo):

6. Los parámetros pueden ser objetos IFormattable
Si parámetros introducidos en una cadena interpolada son objetosIFormattable
, se invocará a su método ToString()
para que sea él mismo el que se formatee: 
7. La cultura por defecto es la del hilo actual
Si vamos a utilizar formateo, este detalle es importante: la cultura aplicable será la activa en el hilo de ejecución actual.
Esto tiene bastante sentido porque este comportamiento es consistente con su equivalente utilizando
String.Format()
. 8. Las cadenas interpoladas actúan como strings
En los ejemplos que hemos visto hasta ahora, las cadenas interpoladas eran meros sustitutos de unstring
clásico. El compilador de C# detecta este escenario y durante el proceso de compilación son transformadas en una llamada al método string.Format()
como podemos observar en el siguiente código: 
Por cierto, si queréis ver cómo funciona esta transformación por dentro, podéis hacer pruebas en la dirección http://tryroslyn.azurewebsites.net/, un sitio web powered by Roslyn en el que podréis introducir código C# 6.0 y ver el resultado descompilado. Muy interesante y recomendable :)
9. Las cadenas interpoladas también actúan como objetos IFormattable
Si el compilador detecta que estamos usando una cadena interpolada en lugar de un objetoIFormattable
, actuará de forma ligeramente diferente, lo que nos da alguna ventaja si queremos intervenir en el proceso de formateo de estas cadenas. Fijaos en este código, donde pasamos la cadena interpolada a una función cuyo parámetro se espera que sea
IFormattable
: 
En este caso, el código equivalente generado por Roslyn será el siguiente. Se puede observar que no ha sido transformado en una llamada a
String.Format()
sino en una invocación a FormattableStringFactory.Create()
, que construirá el objeto IFormattable
que espera la función ToUpper()
vista anteriormente. 
¿Y por qué es interesante esto? Pues porque esta técnica nos permite crear formateadores personalizados de forma relativamente sencilla.
Por ejemplo, podemos usar esta capacidad para crear funciones que nos ayuden a formatear una cadena en una cultura determinada. El siguiente código, un clásico entre los ejemplos de uso de esta característica, muestra cómo podemos usar una función para formatear usando cultura invariante:

Otros ejemplos muy ingeniosos que he visto consisten en utilizar esta característica para construir cadenas que requieren un tratamiento especial, como puede ser la construcción de una URL, o incluso una sentencia SQL. En ambos casos es interesante “retocar” el proceso de formateo de parámetros, en el primer caso para introducir codificación, y en el segundo para evitar efectos no deseados como inyecciones de script. No dejéis de echar un vistazo al blog de Thomas Levesque para verlos.
10. ¡Soporte para Heredoc!
En el primer vistazo que dimos a la interpolación de cadenas en C# 6 ya comenté que no había visto soporte para Heredoc o cadenas verbatim, un escenario en el que esta característica tenía mucha aplicación. Bien, pues esto parece que por fin ha cambiado, y ahora sí que podemos ya implementar cadenas interpoladas con múltiples líneas de texto.Simplemente tenemos que insertar el carácter $ que caracteriza a las cadenas interpoladas justo antes de la arroba @ que indica el comienzo de la cadena verbatim:

11. Sólo es syntactic sugar, aplicable en tiempo de compilación
Es importante tener en cuenta que esta característica es principalmente lo que solemos denominar syntactic sugar, es decir, una ayuda sintáctica destinada a endulzar la vida del desarrollador, por lo que se resuelve en tiempo de compilación, antes de ejecutar la aplicación.No existe, por tanto, ningún tipo de penalización del rendimiento en runtime por usar esta técnica más allá del que encontraríamos al utilizar
String.Format()
. 12. ¿Uso en versiones del framework anteriores a la 4.6?
Si usamos cadenas interpoladas como purosstring
, comentado en el punto 8 de este post, no tendremos problemas en usar esta característica. Es decir, podremos compilar sin problema nuestra aplicación usando C# 6 aunque el target del proyecto sea un .NET framework anterior al 4.6 y todo funcionará bien. Sin embargo, sí tendremos problemas cuando tratamos cadenas interpoladas como
IFormattable
, y la explicación la tenéis un poco más atrás, en un sutil detalle que hemos deslizado cuando hablábamos del tratamiento de cadenas interpoladas como objetos IFormattable.
Como decíamos, éstas se transformaban en una llamada a FormattableStringFactory.Create()
, lo que obviamente implica que el compilador está asumiendo que esta clase existe, cuando en realidad esto no es así en las versiones anteriores a la 4.6 del framework. En estos casos, la solución consiste únicamente en crear en el proyecto actual las clases FormattableStringFactory y FormattableString, cuyo código fuente podemos obtener desde Github mediante los enlaces anteriores. Y para los perezosos, existe un paquete Nuget (no oficial) que lo hace, y que podemos instalar así:
PM> Install-Package StringInterpolationBridge
Bueno, y es todo, creo ;) Espero que esta revisión en profundidad de la interpolación de cadenas os sea útil para conocer un poco mejor en qué consisten y cómo podrán ayudarnos en nuestro día a día cuando comencemos a trabajar con C# 6.
Publicado en Variable not found.
2 Comentarios:
Muy interesante como siempre, aprovecho para felicitarte por los 9 años del blog. Un saludo.
Muchas gracias, Carlos!
Enviar un nuevo comentario
Backlinks: