jueves, 27 de agosto de 2015

Novedades C# 6.0 (Parte 3)






Vamos a finalizar esta serie de posts de novedades de C# 6.0, entrando en profundidad dentro de los apartados de Name of Expressions, la utilización de Await en los bloques catch y finally, y continuando con las excepciones, acabaremos con una novedad adoptada de Visual Basic, que no es otra que los bloques catchs condicionales o filtrado de excepciones.











Entregas anteriores de novedades C# 6.0

Parte 3




Name of Expressions’, está basado en el nuevo operador nameof. A simple vista, puede parecer que este operador no nos va a cambiar la vida, y de hecho no lo va a hacer, pero va a ayudarnos a gestionar de una forma mucho más eficiente, cualquiera de nuestras menciones a clases, variables, métodos, etc., dentro de nuestro código.

El operador nameof, retorna la descripción de la variable en código transformada a cadena.


var varialbe1 = "valorVariable1";

string nombreVarialbe1EnCodigo = nameof(varialbe1);

Console.WriteLine(nombreVarialbe1EnCodigo);


















Normalmente cuando escribo un post, no me suele gustar utilizar los mismos ejemplos que aparecen en la red de ‘algo’, siempre me gusta crear o pensar uno para la ocasión, que lo haga un poco más único, pero en el caso de ‘Name of Expressions’ el archiconocido ejemplo de validación de parámetros nulos, cumple con su cometido perfectísimamente. Vamos a verlo:


public static string ToUpperToTrim(string source)
{
    if(string.IsNullOrWhiteSpace(source))
    {
        throw new ArgumentNullException($"La variable {nameof(source)}, no puede ser nula/vacia/blanco");
    }

    string resultado = source.Trim().ToUpper();

    return resultado;
}

Este ejemplo, aglutina en un método, un par de operaciones que solemos hacer con asiduidad, cuando comparamos cadenas. Como podemos ver, comprobamos que la cadena tenga valor, para lanzar una excepción controlada en caso de no tenerlo, sin tener que esperar a que el CLR, lo lance por nosotros por acceder a un miembro de una clase null. En el mensaje de la excepción añadidos el nombre del parámetro en código, para que el desarrollador, tenga la mayor información posible del incidente.


Muchos podrían pensar que así también hubiera valido:


throw new ArgumentNullException($"La variable source, no puede ser nula/vacia/blanco");


Pero si por necesidades del desarrollo, se hubiera precisado cambiar el nombre del parámetro, muchos estamos acostumbrados a que el compilador nos cambie automáticamente todas las ocurrencias dentro de nuestro código, por lo que ésta, al estar dentro de una cadena, entre comillas, se hubiera escapado a nuestra refactorización automática.















Nota:

Esto no es del todo cierto, ya que en la última versión de Visual Studio 2015, tenemos una forma de hacer rename con nuevas opciones:


Hacemos click derecho sobre la variable que queremos renombrar y elegimos la segunda opción que nos muestra el menú, Rename.



































Nos aparecerá una serie de opciones donde podremos elegir, que incluya los datos entrecomillados a la hora de renombrar.















Esto es algo más tedioso, y la opción de utilizar el operador nameof, siempre es bastante más cómoda y segura.





Await dentro de bloques Cath y Finally

Este puede que sea la novedad más fácil de explicar, ya que el mismo título, lo dice prácticamente todo.

A modo de introducción, contar que desde la versión 4.5 del Framework, tenemos la posibilidad de marcar nuestros métodos con la palabra reservada async. Esto daba la posibilidad de realizar una espera dentro del método, para una llamada externa, haciendo uso de la palabra reservada await, dando la capacidad de asincronía a nuestros métodos. Esto es una explicación muy elemental del asunto, pero se escapa del objetivo de este post.

En versiones anteriores, cuando teníamos un método marcado con las palabras reservadas async, estábamos obligados a utilizar dentro un await, pero esto solo lo podíamos utilizar dentro del bloque normal de ejecución o dentro del bloque try, pero nunca dentro de un catch o un finnaly. Estas limitaciones se han superado dentro de esta nueva versión.


Ahí va un ejemplo:


public async static void HarceAlgoEstatico()
{
    var task = Task.Run<string>(() =>
    {
        WriteLine($"La taréa a empezado a las {DateTime.Now.ToShortTimeString()}");
        System.Threading.Thread.Sleep(3000);

        return $"Finalizado a las {DateTime.Now.ToShortTimeString()}";
    });

    try
    {
        string a = null;

        string b = a.ToString();

        string resultadoTarea = await task;

        WriteLine($"Después del await, el resultaod es --> {resultadoTarea}");
    }
    catch (Exception ex)
    {
        var resuladoTask = await task;

        WriteLine($"Catch resultado: {resuladoTask}");
    }

}


En nuestro ejemplo el await aparece en un bloque catch, pero igualmente podría aplicarse dentro de un finally, de existir.


Para muestra, un botón. Voy a dejar un pantallazo del básicamente el mismo código, en la versión anterior, con la marca de error del compilador.

























Digo, básicamente, porque he tenido que eliminar las cadenas formateadas con $, ya que estás tampoco compilaban, si alguien tiene dudas de esto que lea el primer post de novedades de C# 6.0.


Filtrado de Excepciones


El filtrado de excepciones, tiene el objetivo de hacer mucho más legible la parte de los catchs de nuestro código. Todos estamos en cierta forma acostumbrados a leer partes de código así:


try
{
    /// ...
}
catch(ArgumentNullException anex)
{

}
catch(InvalidOperationException ioex)
{

}
catch (Exception ex)
{

}


Una sucesión de catchs, colocando en última posición el menos restrictivo.


Para muchos desarrolladores (entre los que me añado), en muchas ocasiones, cuando lanzamos una excepción en código, si no tenemos que utilizarla en ningún caso especial, nos conformamos con elevar un Exception, con su mensaje descriptivo correspondiente, con lo que nos podemos encontrar cosas así:


try
{
    /// ...
}
catch (Exception ex)
{
    if (ex.Message.Contains("BD"))
    {
                    
    }

    if (ex.Message.Contains("Fichero "))
    {

    }

    if (ex.Message.Contains("Mail "))
    {

    }

    /// ...
}



Para que todo quede un poquito más bonito, e intentar emular la vista de diferentes catchs, ahora podemos retocarlo como sigue:

try
{
    /// ...
}
catch(Exception ex) when (ex.Message.Contains("BD"))
{

}
catch (Exception ex) when (ex.Message.Contains("Fichero "))
{

}
catch (Exception ex) when (ex.Message.Contains("Mail "))
{

}
catch (Exception ex)
{

}


La palabra reservada when, hace parte de la magia y nos permite que esto se pueda ver así de bien.