Como muchos ya sabéis, o algunos puede que no, la nueva versión 6.0 de C# ya está en el horno, y será publicada en breve. Esta nueva versión con nombre en código “Roslyn” es parte de la nueva estrategia “Opennes” de Microsoft, y por ese motivo, puede ser encontrado como open source en su repositorio de GitHub.
He estado leyendo artículos durante un tiempo acerca de las nuevas funcionalidades qua va a incorporar desde los sitios oficiales, desde blogs particulares y de gente que ha estado probando el nuevo Visual Studio 2015 Preview. Al final del artículo tenéis los enlaces a las fuentes que he usado para confeccionar esta recopilación.
Algunos artículos describen sus funcionalidades favoritas, mientras otros intentan dar una visión más global. Es este artículo, hago una recopilación de todas (o la mayoría) de las nuevas funcionalidades, y como contribución por mi parte, daré ejemplos sobre ellas, para intentar dar un uso “en la vida real” de cada una.
Si quieres hacerlo rápido, hay un archivo PDF “oficial” enlazado en el sitio GitHub de Roslyn que puedes descargar desde éste enlace, pero a mi me gustaría más si sigues leyendo… aquí hay muchos ejemplos!
Nuevas funcionalidades en C# 6.0 Roslyn
Estas son las funcionalidades planeadas para el lanzamiento de C# 6.0
- Inicializadores en auto-propiedades
Using
estático- Interpolación de strings
await
en bloquescatch
yfinally
- Operador condicional para nulos
- Expresión
nameof
- Uso de
IEnumerable<>
en vez deparams[]
- Inicializadores de eventos
Y estas otras, son funcionalidades que en un principio pudieron verse, pero finalmente han sido descartadas según este artículo de Octubre de 2014.
- Propiedades y funciones por expresiones
- Constructores primarios
- Inicializadores de miembros indexados
Una por una
Haremos una pasada rápida a cada una de las nuevas adiciones, incluyendo ejemplos de la vida real y mi evaluación personal acerca de la utilidad que puedan llegar a tener.
Inicializadores en auto-propiedades
Cuando tienes propiedades que debes inicializar con valores por defecto en tu clase, puedes hacer esto:
private string _myProperty = "Valor por defecto"; public string MyProperty { get { return _myProperty; } set { _myProperty = value; } }
o esto:
public class MyClass { public string MyProperty { get; set; } public MyClass() { MyProperty = "Valor por defecto"; } }
Con C# 6.0, puedes añadir valores por defecto al definir la auto-propiedad de esta manera:
public string MyProperty { get; set; } = "Valor por defecto";
Nivel de utilidad: alto
using
estático
Cuando usamos una clase estática para hacer muchas llamadas a sus métodos, el código puede ser un poco espeso, y las múltiples repeticiones del nombre de la clase pueden llegar a ocultar el propósito del código.
Veamos cómo se deben hacer las cosas con la versión actual de C#:
private void LogATodo(string logString) { MiTremendoLoggerEstatico.LogAConsola(logString); if (MiTremendoLoggerEstatico.LogADBActivado && MiTremendoLoggerEstatico.ConectadoADB()) MiTremendoLoggerEstatico.LogADB(logString); if (MiTremendoLoggerEstatico.LogANubeActivado && MiTremendoLoggerEstatico.ConectadoANube()) MiTremendoLoggerEstatico.LogANube(logString); }
Con los nuevos using
estáticos de C# 6.0, la misma funcionalidad es mucho más legible:
using MiNamespace.MiTremendoLoggerEstatico; // esto es una clase! private void LogATodo(string logString) { LogAConsola(logString); if (LogADBACtivado && ConectadoADB()) LogADB(logString); if (LogANubeActivado && ConectadoANube()) LogANube(logString); }
Bufff! mucho mas legible verdad?
Nivel de utilidad: medio
Interpolación de strings
La interpolación de strings hará mas fácil mezclar strings con valores, como se hace ahora con string.Format
pero sin la necesidad de llamar a ningún método, y haciendo la lectura del string más sencilla al no usar números de parámetro, sino nombres de variable reales. Ahora se hace así:
return string.Format("Tienes {0} mensajes. " +"El primero a las {1} y el último a las {2}", msgCount, firstMsg, lastMsg);
Con C# 6.0 harás algo así:
return $"Tienes {msgCount} mensajes. " +"El primero a las {firstMsg}, " +"y el último a las {lastMsg}";
La sintaxis todavía no es definitiva, pero será algo bastante similar al ejemplo.
Actualización 02/02: Según la última CTP descargada estos días, la sintaxis definitiva pasa a ser prefijando el string a interpolar con el símbolo $ y ya no es necesario prefijar con la contrabarra cada interpolación.
Nivel de utilidad: medio
await
en bloques catch
y finally
Hoy en día muchas aplicaciones funcionan en modo multi-hilo y hacen uso de las funcionalidades await
y async
de C# 5.0.
Uno de los problemas de la implementación de estas funciones en C# 5.0 es que la palabra clave await
no está permitida en los bloques catch
ni finally
, obligándonos a hacer cosas estrafalarias como estas:
string result = null; bool tengoResult; Exception ex; try { result = await new ApiClient().GetContentAsync(new Uri( "http://esta-url.no.va")); tengoResult = true; } catch (Exception ex) { tengoResult = false; } if (!tengoResult) await LogClass.WriteError(ex); return result;
Con C# 6.0, await
ya esta permitido en los bloques catch
y finally
, y la misma funcionalidad puede ser conseguida de una forma mucho más elegante:
try { return await new ApiClient().GetContentAsync(new Uri("http://esta-url.no.va")); } catch (Exception ex) { await LogClass.WriteError(ex); return null; }
Nivel de utilidad: alto
Operador condicional para nulos
Una de las funcionalidades que mas esperaba por mi parte. Estoy ya realmente cansado de cosas como esta:
if (Factura != null && Factura.Cliente != null && Factura.Cliente.Direccion != null && Factura.Cliente.Direccion.CodigoPostal == CP_CORRECTO) { ....... }
Ahora nos podremos ahorrar el tener que comprobar cada objeto padre por si es nulo usando el operador condicional para nulos ?.
de esta manera:
if (Factura?.Cliente?.Direccion?.CodigoPostal == CP_CORRECTO) { ....... }
Esto si que es ahorrar código!
Nivel de utilidad: alto
Expresión nameof
Otra bonita mejora. A veces necesitas trabajar con los identificadores como strings. El problema es que pasar sus nombres como “magic strings” es una práctica que no es muy recomendable:
var label = myReflectionObj.GetLabelFor("MiPropiedad");
El problema de esta aproximación es que usar la constante string “MiPropiedad”, aunque no dará problemas de compilación, si hará fallar la aplicación si cambiamos el nombre de la propiedad en nuestra clase y olvidamos cambiarlo en esta llamada (es bastante habitual).
En C# 6.0 podremos usar nameof
para esto:
var label = myReflectionObj.GetLabelFor(nameof(myObj.MiPropiedad));
Este código si es a prueba de refactorización. Si cambiamos el nombre de la propiedad mediante refactorización donde sea, también será cambiada aquí, y si no, el proyecto no va a compilar.
Nivel de utilidad: medio
Uso de IEnumerable<>
en vez de params[]
Yo uso la funcionalidad params[]
a menudo en mis métodos para pasar un número variable de parámetros. En C# 6.0 podrás definir el parámetro como IEnumerable<>
. Eso te permitirá aprovechar la naturaleza “lazy” (puedes ver éste artículo si no sabes lo que es lazy loading) de IEnumerable<>
.
Veamos un ejemplo. En este método SeleccionarPorNombre
tomamos una acción a ejecutar sobre una colección de candidatos cuyo nombre comience por “Adams”. Cuando hacemos la llamada, convertimos el IEnumerable
de la base de datos a un Array
, causando iteración sobre la misma y cargando TODOS los registros de la BBDD.
public void SelectByName(string partialName, Action<MyEntity> action, params MyEntity[] candidates) { candidates.Where(c => c.Name.StartsWith(partialName)).ToList().ForEach(action); } IEnumerable<MyEntity> allEntities = MyDB.GetAllEntities(); new Test().MarkAllA("Adams", t => { t.Selected = true; }, allEntities.ToArray());
Con C# 6.0, podemos mantener la cadena “lazy” hasta el momento de filtrar los candidatos, de esa manera solo recuperaremos de la BBDD los elementos que necesitamos, y no todos.
public void SelectByName(string partialName, Action<MyEntity> action, params IEnumerable<MyEntity> candidates) { candidates.Where(c => c.Name.StartsWith(partialName)).ToList().ForEach(action); } IEnumerable<MyEntity> allEntities = MyDB.GetAllEntities(); new Test().MarkAllA("Adams", t => { t.Selected = true; }, allEntities);
Nivel de utilidad: medio
Inicializadores de eventos
Con la nueva versión 6.0, podremos inicializar los manejadores de eventos como si fuesen cualquier otra propiedad de esta manera:
var b = new MyClass { Id = "ABC", OnChange += myClassOnChange };
Nivel de utilidad: bajo
Funcionalidades descartadas para esta versión
Según este post oficial, algunas de las funcionalidades planeadas para C# 6.0 han sido descartadas para el lanzamiento final. Aquí estan algunas de ellas:
Propiedades y funciones por expresiones
Una lástima… esta era una de mis favoritas! Imagina en vez de hacer esto:
public string FormattedDate { get { return string.Format("{0:d}",this.TheDate); } }
Poder hacer esto:
public string FormattedDate => string.Format("{0:d}",this.TheDate);
Bonito, eh? Pues tendremos que esperar a versiones futuras de C# para verlo.
Constructores primarios
Esta funcionalidad permitía ahorrarnos el tener que crear constructores para inicializar valores de la clase.
En vez de esto:
public class MyClass { private string _field1; public MyClass(string field1) { _field1 = field; } }
Podíamos hacer esto:
public class MyClass(string field1) { private string _field1 = field; }
Yo veía esta un poco rara… prefiero la manera actual de implementar constructores.
Inicializadores de miembros indexados
Los inicializadores de estructuras habían sido renovados para esta versión, pero finalmente lo han retirado y las cosas seguirán como estan.
La manera actual de inicializar una colección es esta:
private Collection<int,string> myCollection = new Collection<int,string> { { 0, "Element Zero" }, { 1, "Element One" } };
La nueva propuesta era esta:
private Collection<int,string> myCollection = new Collection<int,string> { [0] = "Element Zero", [1] = "Element One" };
NO era demasiado cambio… nada por lo que preocuparse.
Fuentes
Para confeccionar éste artículo, he tomado ideas e información de los siguientes:
- MSDN Magazine: A C# 6.0 Language Preview
- MSDN Magazine: The New and Improved C# 6.0
- C# Frequently Asked Questions: New Features in C# 6
- dotnetcurry.com: C# 6.0 What’s new
- Kunal-Chowdhury.com: What’s new in C# 6.0? serie de artículos
Gracias y crédito para todos los autores!
Gracias!
Más cosas en breve. Manténte conectado al blog!
Joan Vilariño
Latest posts by Joan Vilariño (see all)
- Factoría de Objetos: Crea objetos con Expression Trees y atributos - 17/02/2016
- Nuevo año, nueva dirección, nuevo hosting! - 02/12/2015
- Usando
dynamic
overloads - 21/10/2015
Comentarios recientes