Roberto Sánchez - Programador/Desarrollador aplicaciones .NET

NOTICIAS

Visual Studio 2017.

Microsoft nos vuelve a sorprender con su más impresionante herramienta de desarrollo para programadores. Visual Studio, en su versión release 2017, nos ofrece todas las funcionalidades de Visual Studio 2015 y algunas interesantes novedades:

- Se ha mejorado la productividad con mejoras en la navegación por el código.

- La herramienta 'IntelliSense' permite una refactorización más clara.

- Nuevas funciones de depuración.

- Se apuesta firmemente por la nube, concretamente por 'Azure', facilitando el desarrollo y la implementación de servicios en la nube.

- Gracias a Xamarin, este Visual Studio ahora permite crear aplicaciones para dispositivos móviles como Android y iOS de una manera mucho más eficiente incluso que los propios IDEs de Google y Apple. Los desarrolladores pueden crear sus aplicaciones con Apache, Cordova o C++.

- El proceso de instalación ha sido simplificado al máximo, así como el tiempo de arranque, pudiendo tener el IDE funcionando en mucho menos tiempo que antes.

En el siguiente enlace puedes ver la lista completa con todos los cambios de Visual Studio 2017 y descargar la nueva versión. Salvo que necesitemos las versiones Professional o Enterprise, podemos descargar y utilizar de forma totalmente gratuita la versión Visual Studio Community 2017, enfocada principalmente a los estudiantes y los desarrolladores de software libre y programadores individuales.

Nuevo producto disponible: EqMonitor.

¿Preocupado por la seguridad de los datos en su empresa? ¿Desea controlar la fuga de datos de los terminales de su empresa?

Si desea proteger la información sensible, con la aplicación EqMonitor podrá controlar las fugas de datos que se realicen en los equipos y terminales de su empresa. EqMonitor transmite alertas por correo electrónico en el mismo momento del intento de fuga de datos. Información del día y la hora exactas, así como del nombre del equipo afectado.

Más información EqMonitor

Novedades C# 7.0.

Cuando lea este artículo, tenga en cuenta que actualmente se tratan ideas de lo que se puede incluir en C# 7. Algunas son ideas que simplemente se han debatido en el equipo de desarrolladores de Microsoft, mientras que otras se pueden considerar implementaciones experimentales. En cualquier caso, ninguno de los conceptos está definido, muchos ni siquiera se han ejecutado e incluso los que están más avanzados podrían eliminarse en fases finales de la creación del lenguaje.


TUPLAS.

Una característica que se está considerando para C# 7 son las tuplas. Es un tema que ha surgido en varias ocasiones en las versiones anteriores del lenguaje, pero aún no se ha llevado a producción. La idea es que fuera posible declarar tipos en conjuntos de forma que una declaración pueda contener más de un valor y, a la vez, métodos que puedan devolver más de un valor. Observe el código de ejemplo siguiente para entender el concepto:

public class Person
{
    public readonly (string firstName, int lastNames) Names;
    public Person((string FirstName, string LastName)) names, int Age)
    {
        Names = names;
    }
}

Como se muestra en la lista, con la compatibilidad con tuplas es posible declarar un tipo como una tupla (y así tener dos o más valores). Esto se puede aprovechar siempre que se pueda aprovechar un tipo de datos, como un campo, un parámetro, una declaración de variable o incluso la devolución de un método. Por ejemplo, el fragmento de código siguiente devolvería una tupla de un método:

public (string FirstName, string LastName) GetNames(string! fullName)
{
    string[] names = fullName.Split(" ", 2);
    return (names[0], names[1]);
}
public void Main()
{
    (string first, string last) = GetNames("Roberto Sánchez");
}

En esta lista hay un método que devuelve una tupla y una declaración de variable de los elementos primero y último a los que se asigna el resultado de 'GetNames'. Tenga en cuenta que la asignación se basa en el orden dentro de la tupla (no en los nombres de las variables receptoras). Teniendo en cuenta los enfoques alternativos que se usan hoy en día (una matriz o una colección, un tipo personalizado, parámetros de salida), las tuplas son una opción interesante.


COINCIDENCIA DE PATRONES.

La coincidencia de patrones también es un tema habitual en los debates del equipo de diseño de C# 7. Quizá una de las representaciones de esto que mejor se entienden serían las instrucciones 'switch' expandidas que admitían patrones de expresiones en las instrucciones 'case', en lugar de solo constantes. (Para que correspondiese a la instrucción 'case' expandida, el tipo de la expresión 'switch' tampoco estaría limitado a tipos que tengan valores constantes correspondientes). Con la coincidencia de patrones, podría consultar la expresión 'switch' en busca de un patrón, como si la expresión 'switch' es un tipo concreto, un tipo con un miembro determinado o incluso un tipo que coincida con un "patrón" o una expresión concretos. Por ejemplo, observe como el elemento 'obj' podría ser de tipo 'Point' con un valor de 'x' mayor que 2:

object obj;
// ...
switch (obj)
{
    case 42:
        // ...
        break;
    case Color.Red:
        // ...
        break;
    case string s:
        // ...
        break;
    case Point(int x, 42) where(Y › 42);
        // ...
        break;
    case Point(490, 42);
        // ...
        break;
    default:
        // ...
        break;
}

Curiosamente, si se especifican expresiones como instrucciones 'case', también sería necesario permitir las expresiones como argumentos en instrucciones 'goto case'.

Para admitir la instrucción case de tipo 'Point', sería necesario que hubiese algún tipo de miembro en 'Point' que controlara la coincidencia de patrones. En este caso, lo que se necesita es un miembro que acepte dos argumentos de tipo 'int'. Un miembro como por ejemplo el siguiente:

public static bool operator is (Point self out int x, out int y) { ... }

Observe que sin la expresión 'where', nunca se habría alcanzado la línea case 'Point(490, 42)', por lo que el compilador habría emitido un error o una advertencia.

Uno de los factores que limitan la instrucción switch es que no devuelve un valor, sino que ejecuta un bloque de código. Una característica agregada de la coincidencia de patrones podría ser la compatibilidad con una expresión 'switch' que devolviese un valor, como en:

string text = match (e) { pattern => expression; ...; default => expression }

De forma similar, el operador 'is' podría admitir la coincidencia de patrones, lo que permitiría no solo una comprobación de tipos, sino que haría posible la compatibilidad con una consulta más genérica sobre si existen miembros concretos en un tipo.


REGISTROS.

En una continuación de la sintaxis de la declaración abreviada "constructor" que se consideró (y finalmente se rechazó) en C# 6.0, existe compatibilidad para insertar la declaración de constructor dentro de la clase de definición; un concepto que se conoce como "registros". Por ejemplo, observe la declaración siguiente:

class Person(string Name, int Age);

Esta instrucción simple generaría automáticamente lo siguiente:

• Un constructor:


public Person(string Name, int Age)
{
    this.Name = Name;
    this.Age = Age;
}

• Propiedades de sólo lectura, creando por tanto un tipo inmutable.

• Implementación de igualdad (como 'GetHashCode', 'Equals', 'operador ==', 'operador !=', etc.).

• Una implementación predeterminada de 'ToString'.

• Compatibilidad con la coincidencia de tipo del operador 'is'.

Aunque se genera una cantidad de código considerable (teniendo en cuenta que solo se crea una pequeña línea de código), se espera que pueda proporcionar un ahorro igual de significativo para codificar manualmente lo que en esencia son implementaciones reutilizables. Además, se puede considerar que todo el código es "predeterminado" en el sentido de que si se implementa explícitamente cualquier parte, tendría precedencia e impediría la generación del mismo miembro.

Uno de los asuntos problemáticos asociados con los registros es la forma de controlar la serialización. Presumiblemente, el aprovechamiento de los registros como objetos de transferencia de datos (DTO) es bastante habitual y, sin embargo, no está claro lo que se puede hacer (ni si es siquiera posible) para admitir la serialización de este tipo de registros.

Junto a los registros está la compatibilidad con las expresiones with. Las expresiones with permiten la creación de instancias de un nuevo objeto basándose en un objeto existente. Dada la declaración de objeto person, podría por ejemplo crear una nueva instancia mediante la expresión with siguiente:

Person roberto = new Person("Roberto Sánchez", 42);
Person humperdink = roberto with { Name = "Prince Humperdink" };

El código generado que corresponde a la expresión with sería algo como:

Person humperdink = new Person(Name: "Prince Humperdink", Age: roberto.42);

Sin embargo, una sugerencia alternativa es que en lugar de depender de la firma del constructor de la expresión 'with', podría ser preferible convertirla en la invocación de un método 'With', como en:

Person humperdink = roberto.with(Name: "Prince Humperdink", Age: roberto.42);

SECUENCIAS ASINCRÓNICAS.

Para mejorar la compatibilidad con la asincronía en C# 7, el concepto de procesamiento de secuencias asincrónicas es muy interesante. Por ejemplo, dado un elemento 'IAsyncEnumerable', con una propiedad 'Current' y un método 'Task‹bool› MoveNextAsync', podría recorrer en iteración la instancia de 'IAsyncEnumerable' mediante 'foreach' y dejar que el compilador se ocupase de la invocación de cada uno de los miembros de la secuencia asincrónicamente (realizando un proceso 'await' para descubrir si hay otro elemento en la secuencia, posiblemente un canal, que haya que procesar). Hay una serie de advertencias relacionadas que se deben analizar, la menos importante de las cuales es el sobredimensionamiento de LINQ que podría producirse con todos los operadores de consultas estándares de LINQ que devuelven 'IAsyncEnumerable'. Además, no está claro cómo exponer la compatibilidad de 'CancellationToken' e incluso 'Task.ConfigureAwait'.


C# EN LA LÍNEA DE COMANDOS.

Como un amante de la forma en que Windows PowerShell consigue que Microsoft.NET Framework esté disponible en la interfaz de la línea de comandos (CLI), un área que me fascina en particular (y posiblemente mi característica favorita de las que se están considerando) es la compatibilidad para usar C# en la línea de comandos; un concepto que se conoce de forma más genérica como compatibilidad con lectura, evaluación, impresión y bucle (REPL). Como cabe esperar, la compatibilidad con REPL estaría acompañada de scripts de C# que no requieren todas las formalidades habituales (como la declaración de clases) en escenarios comunes que no necesiten ese tipo de cuestiones. Sin un paso de compilación, REPL necesitaría nuevas directivas para hacer referencia a ensamblados y paquetes NuGet, junto con la importación de archivos adicionales. La propuesta actual que se está debatiendo admitiría:

• '#r' para hacer referencia a un paquete NuGet o un ensamblado adicionales. Una variación sería '#r!', que permitiría el acceso incluso a miembros privados, aunque con algunas restricciones. (Esto está pensado para escenarios en los que se accede a ensamblados de los que tiene el código fuente).

• '#l' para incluir directorios completos (igual que F#).

• '#load' para importar un archivo de script de C# adicional, de la misma forma que lo agregaría al proyecto con la excepción de que ahora el orden es importante. (Tenga en cuenta que podría no admitirse la importación de un archivo .cs, ya que los espacios de nombres no se permiten en los scripts de C#).

• '#time' para activar los diagnósticos de rendimiento durante la ejecución.

Puede esperar que la primera versión de REPL de C# se publique con Visual Studio 2015 Update 1 (junto con una ventana interactiva actualizada que admita el mismo conjunto de características).


RESUMEN.

Con el material de todo un año, queda muchísimo para explorar todo lo que el equipo de diseño ha estado haciendo e, incluso con las ideas que he explicado, hay muchos más detalles (tanto advertencias como ventajas) que se deben considerar. Sin embargo, espero que ya tenga una idea de lo que está explorando el equipo y cómo se está buscando mejorar el ya de por sí brillante lenguaje C#.

Novedades C# 6.0.

Las características específicas de C# 6.0 se implementan por completo en el compilador, sin depender de una actualización de Microsoft .NET Framework o en tiempo de ejecución. Por lo tanto, se puede adoptar C# 6.0 para el desarrollo sin tener que actualizar .NET Framework para el desarrollo o la implementación. De hecho, la instalación del compilador C# 6.0 de esta versión implica poco más que instalar una extensión de Visual Studio 2013 o directamente Visual Studio 2015, que a su vez actualizan los archivos de destino de MSBuild.


MIEMBROS INDEXADOS E INICIALIZADORES DE ELEMENTOS.

[TestMethod]
public void DictionaryIndexWithoutDotDollar()
{
    IDictionarystring , string› builtInDataTypes = new IDictionarystring , string›()
    {
        { "Byte", "0 to 255." },
        { "Boolean", "True or false." },
        { "Object", "An object." },
        { "String", "A string of Unicode characters." },
        { "Decimal", "±1.0 × 10e-28 to ±7.9 × 10e28." },
    };
    Assert.AreEqual("True or false.", builtInDataTypes["Boolean"]);
}

Aunque un poco oculta por la sintaxis, el código fuente anterior no es más que una colección de nombres y valores. Como tal, la sintaxis podría ser considerablemente más clara:‹index› = ‹value›. C# 6.0 hace que esto sea posible mediante los inicializadores de objetos de C# y una nueva sintaxis de miembros de índice. Los siguientes son inicializadores de elementos basados en entero:

var cppHelloWorldProgram = new Dictionaryint, string
{
    [10] = "main() {", [20] = " printf(\"hello, world\")", [30] = "}"
};
Assert.AreEqual(3, cppHelloWorldProgram.Count);

Tenga en cuenta que aunque este código utiliza un entero para el índice, Dictionary‹TKey,TValue› puede admitir cualquier tipo como índice (siempre que sea compatible con IComparable‹T›). En el siguiente ejemplo se presenta una cadena para el tipo de datos de índice y se utiliza un inicializador de miembro indexado para especificar valores de elementos:

Dictionarystring, string› builtInDataTypes = new Dictionarystring, string
{
    ["Byte"] = "0 to 255.",
    ["Boolean"] = "True or false.",
    ["String"] = "A string of Unicode Characters.",
    ["Decimal"] = "±1.0 × 10e?28 to ±7.9 × 10e28.",
};

PROPIEDADES AUTOMÁTICAS CON INICIALIZADORES.

A veces, la inicialización de una clase hoy día puede ser engorrosa. Tomemos, por ejemplo, el caso sencillo de un tipo de colección personalizada (como Queue‹T›) que internamente mantiene una propiedad privada System.Collections.Generic.List‹T› para una lista de elementos. Cuando se crea una instancia de la colección, se tiene que inicializar la cola con la lista de elementos que va a contener. Sin embargo, las opciones razonables para hacerlo con una propiedad requieren un campo de respaldo junto con un inicializador o un constructor else, la combinación de los cuales prácticamente dobla la cantidad de código requerido.

Con C# 6.0, hay un atajo en la sintaxis: los inicializadores de propiedades automáticas. Ahora se pueden asignar a propiedades automáticas directamente, tal como se muestra a continuación:

class Queue‹T›
{
    private List‹T› InternalCollection { get; } = new List‹T›;
}

Observe que en este caso la propiedad es de solo lectura (no se ha definido ningún establecedor). Sin embargo, la propiedad puede asignarse también en tiempo de declaración. Además se admite una propiedad de lectura/escritura con un establecedor.


CONSTRUCTORES PRINCIPALES.

Junto a las mismas líneas de los inicializadores de propiedades, C# 6.0 proporciona atajos sintácticos para la definición de un constructor. Tenga en cuenta la prevalencia del constructor C# y la validación de propiedades que se muestra en el siguiente código fuente:

[Serializable]
public class Patent
{
    public Patent(string title, string yearOfPublication)
    {
        Title = title;
        YearOfPublication = yearOfPublication;
    }
    public Patent(string title, string yearOfPublication, IEnumerable‹string› inventors) : this(title, yearOfPublication)
    {
        Inventors = new Liststring›();
        Inventors.AddRange(inventors);
    }
    [NonSerialized]
    private string _Title;
    public string Title
    {
        get
        {
            return Title;
        }
        set
        {
            if (value = null)
                throw new ArgumentNullException("Title");
            _Title = value;
        }
    }
    public string YearOfPublication { get; set; }
    public Liststring› Inventors { get; private set; }
    public string GetFullName()
    {
        return string.Format("{0} ({1})", Title, YearOfPublication);
    }
}

INSTRUCCIONES DE UTILIZACIÓN ESTÁTICA.

Otra característica de la sintáctica de C# 6.0 es la introducción de la utilización estática. Con esta característica, es posible eliminar una referencia explícita al tipo cuando se invoca un método estático. Además, la utilización estática permite introducir solo los métodos de extensión de una clase específica, en lugar de todos los métodos de extensión de un espacio de nombres. El siguiente código fuente proporciona el ejemplo "Hello World" de utilización estática en el espacio de nombres System.Console:

using System;
using System.Console;
public class Program
{
    private static void Main()
    {
        ConsoleColor textColor = ForegroundColor;
        try
        {
            ForegroundColor = ConsoleColor.Red;
            WriteLine("Hello, my name is Roberto Sánchez... Who are you?: ");
            ForegroundColor = ConsoleColor.Green;
            string name = ReadLine();
            ForegroundColor = ConsoleColor.Red;
            WriteLine("I must know.");
            ForegroundColor = ConsoleColor.Green;
            WriteLine("Get used to disappointment.");
        }
        finally
        {
            ForegroundColor = textColor;
        }
    }
}

En este ejemplo, el calificador 'Console' se ha eliminado un total de nueve veces. Ciertamente, el ejemplo es forzado, pero aun así, queda claro el concepto. Con frecuencia un prefijo de tipo en un miembro estático (incluidas las propiedades) no agrega un valor significativo y si se elimina produce un código más fácil de escribir y leer.


EXPRESIONES DE DECLARACIONES.

No es raro que, al escribir una instrucción, surja la necesidad de declarar una variable específicamente para dicha instrucción. Tomemos dos ejemplos: al codificar una instrucción 'int.TryParse', se da cuenta de que necesita declarar una variable para el argumento de salida en la que se almacenarán los resultados del análisis; al escribir una instrucción 'for', descubre que necesita almacenar en caché una colección (como un resultado de consulta LINQ) para evitar volver a ejecutar la consulta varias veces y, para ello, interrumpe el proceso de escribir la instrucción 'for' para declarar una variable.

Para abordar estos inconvenientes y otros similares, C# 6.0 introduce las expresiones de declaraciones. Esto significa que no se tienen que limitar las declaraciones de variables a instrucciones sólo, sino que también se pueden utilizar en expresiones. El siguiente código fuente proporciona dos ejemplos:

public string FormatMessage(string attributeName)
{
    string result;
    if (!Enum.TryParse(FileAttribbutes›(attributeName, out var attributeValue))
        result = string.Format("'{0}' is not one of possible {2} option combinations ({1})", attributeName, string.Join(",", string[] fileAttributeNames =
          Enum.GetNames(typeof(FileAttributes))), fileAttributeNames.Length);
    else
        result = string.Format("'{0}' has a corresponding value of {1}", attributeName, attributeValue);
    return result;
}

MEJORAS DEL CONTROL DE EXCEPCIONES.

Hay dos nuevas funciones para el control de excepciones en C# 6.0. La primera es una mejora de la sintaxis de 'async' y 'await' y la segunda es la compatibilidad para el filtrado de excepciones.

try
{
    WebRequest webRequest = WebRequest.Create("http://www.rsoftware.es/");
    WebResponse webResponse = await webRequest.GetResponseAsync();
}
catch (WebException webException)
{
    await WriteErrorToLog(webException);
}

La otra mejora de excepciones en C# 6.0 (soporte para filtros de excepciones) actualiza el lenguaje con otros lenguajes .NET, concretamente Visual Basic .NET y F#. El siguiente código fuente muestra los detalles de esta característica:

using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.ComponentModel;
[TestMethod][ExpectedException(typeof(Win32Exception))]
public void ExceptionFilter_DontCatchAsNativeErrorCodeIsNot42()
{
    try
    {
        throw new Win32Exception(Marshal.GetLastWin32Error());
    }
    catch (Win32Exception exceptionWin32)
    {
        if (exceptionWin32.NativeErrorCode == 0x00042)
            Assert.Fail("No catch expected.");
    }
}

FORMATOS DE LITERALES NUMÉRICOS ADICIONALES.

C# 6.0 introducirá un separador de dígitos, el bajo subrayado '_', como medio de separar los dígitos en un literal numérico (decimal, hexadecimal o binario). Los dígitos se pueden dividir en agrupaciones que tengan significado en el escenario. Por ejemplo, el valor máximo de un entero se puede agrupar por millares:

int number = 2_147_483_647;

Es probable que el separador de dígitos sea especialmente útil para el nuevo literal binario numérico de C# 6.0. Aunque no es necesario en todos los programas, la disponibilidad de un literal binario podría mejorar el mantenimiento al trabajar con lógica binaria o con enumeraciones basadas en indicadores.

Ahora, con literales numéricos binarios, puede mostrar con más claridad los indicadores que están establecidos y los que no. Esto sustituye la notación hexadecimal mostrada en los comentarios o el enfoque de desplazamiento calculado en tiempo de compilación:

Encrypted = 1‹‹14;

Microsoft .NET Framework 4.6.2 Preview

· Sistemas operativos compatibles:

- Windows 7 SP1 (x86 y x64).

- Windows 8.1 (x86 y x64).

- Windows 10.

- Windows Server 2008 R2 SP1 (x64).

- Windows Server 2012 (x64).

- Windows Server 2012 R2 (x64).

· Requisitos mínimos de hardware:

- Procesador de 1 GHz o más rápido.

- 512 MB de RAM.

- Windows 10.

- 2,5 GB de espacio disponible en el disco duro (x86).

Esta versión de .NET Framework se ejecuta en paralelo con .NET Framework 3.5 SP1 y versiones anteriores, pero permite realizar una actualización local de .NET Framework 4, .NET Framework 4.5, .NET Framework 4.5.1, .NET Framework 4.5.2, .NET Framework 4.6 y .NET Framework 4.6.1.

Descarga desde Microsoft