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

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.

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:

Gracias y crédito para todos los autores!

Gracias!

Más cosas en breve. Manténte conectado al blog!

Follow me

Joan Vilariño

Senior .NET Developer at Ohpen
Follow me