Algunas Nuevas Características de C# 3 (Visual Studio 2008)

Como algunos ya sabeis, Visual Studio 2008 viene con el .NET Framework 3.5, que incluye una buena cantidad de mejoras y novedades con respecto al framework 2.0 que viene con Visual Studio 2005. Algunas de esas características forman parte del trabajo realizado para Windows Vista, pero hay muchas otras de igual o mayor interés para los desarrolladores.

Variables sin tipo, tipos anónimos e inicializadores de objeto:

¿Qué pasa si necesitas un sitio donde guardar información pero no sabes a priori de qué tipo? Fácil, declaras la variable sin especificar su tipo y permites que sea C# quien determine el tipo real de los datos que vas a almacenar.
Por ejemplo, si queremos tener un diccionario que indexa una lista de enteros en base a una cadena (de forma similar a los arrays asociativos que existen en PHP) podríamos hacerlo así:

// Framework 2.0:
Dictionary <string , List<int>> ejemplo = new Dictionary </string><string , List<int>>();
// Framework 3.0:
var ejemplo = new Dictionary </string><string , List<int>>();

Por supuesto, tenemos que inicializar la variable sin tipo en cuanto la declaremos, para que el compilador pueda decidir en tiempo de compilación qué tipo tendrá la variable, ya sea un tipo predefinido como int, una clase creada por el usuario, o un tipo anónimo (hablo sobre ellos un poco más adelante).

De la misma forma se pueden declarar arrays sin tipo, como en el siguiente ejemplo:

// En este caso se crea un array de tipo Int32 con los elementos indicados.
var potenciasDeDos = new [] {2, 4, 8, 16, 31, 64, 128, 256, 512};

Los tipos o clases anónimas, por definición, no tienen nombre. Eso significa que se pueden considerar como definiciones de clase de usar y tirar. La verdadera importancia de estos “tipos anónimos” aparece cuando consideramos LINQ, Language INtegrated Queries, ya que dependiendo de la consulta que realicemos, obtendremos unos datos u otros, de forma que C# lo que hace es crear una clase anónima con los campos devueltos por la consulta LINQ para que se pueda acceder a ellos fácil y rápidamente.

Un tipo anónimo se define así:

var cosa = new {
    Name = "Botellín de Guiness",
    Price = 1.57,
    Description = "Un mal sustituto de una auténtica Guiness, servida de barril en varias tiradas."
};

Como se puede ver, hemos usado una declaración sin tipo para inicializar un conjunto de datos con aspecto de objeto de forma que el compilador entiende que es un objeto, pero al no pertenecer a una clase definida, el compilador lo define automáticamente como objeto de tipo anónimo.

Además, se presenta otra característica interesante: hemos inicializado los valores de los atributos de clase sin necesitar un constructor. Esto es lo que se conoce como inicializadores de objeto, y básicamente permiten asignar el valor que queramos a un objeto de cualquier tipo que haya sido creado usando el constructor por defecto. A continuación veremos un par de ejemplos de cómo usar los inicializadores de objeto para simplificar la escritura del código:

//Inicialización de un objeto con C#2
Cerveza botellin = new Cerveza();
botellin.marca = "Guiness";botellin.temperatura = 5;
botellin.caducidad = Datetime.Now.AddYears(2);
CajaCerveza.Add(botellin);

//Inicialización de un objeto con los inicializadores en C#3
Cerveza botellin = new Cerveza() {
    marca = "Guiness",
    temperatura = 5,
    caducidad = Datetime.Now.AddYears(2)
};
CajaCerveza.Add(botellin);

//O también podemos hacer esto:
CajaCerveza.Add(new Cerveza() {
    marca = "Guiness",
    temperatura = 5,
    caducidad = Datetime.Now.AddYears(2)
});

Expresiones Lambda:

Expresión Lambda suena a forma terrorífica de arte abstracto, pero en realidad es una forma de decir “función anónima”. En C#3 las funciones anónimas se escriben con el operador “=>” , de forma que lo que queda a la izquierda del operador son los parámetros, y lo que queda a la derecha es el cuerpo de la función anónima. Por ejemplo:

x => x+1;
() => return new SalirATomarGuiness();
(x, y) => {
    var suma = x + y;
    return suma;
}

Las ventajas proporcionadas por esta sintaxis pueden no ser evidentes, a no ser que comparemos lo que pasa entre C#2 y C#3:

//Tenemos una lista de palabras
var palabras = new List</string><string> { "mola", "Guiness", "tomar", "me" };
//Ordenar por longitud de palabra, al estilo C#2
Words.Sort(delegate(string a, string b)
{
    return a.Length.CompareTo(b.Length);
});
//Ordenar por longitud de palabra, al estilo C#3
palabras.Sort((a, b) => a.Length.CompareTo(b.Length));

// Show results.
foreach (string palabreja in palabras)
    Console.Write(palabreja + " ");

La salida es “me mola tomar Guiness” en ambos casos. Como podemos ver, el uso de estas funciones anónimas es mucho más sencillo que el tradicional uso de delegados, y además, dependiendo de la situación, ¡nos podemos ahorrar el tener que declarar un delegado como atributo de clase! Además, nos fijamos en que no declaramos tipo al crear el método anónimo, ¿adivinamos por qué? (pista: mirar sección anterior 😛 )

Bueno, este post está siendo más largo de lo que me gustaría, así que dejaré el tema de LINQ (y cómo explota los tipos anónimos, expresiones Lambda y etc) para otro día.

Anuncios

Cómo enviar un email con C#

mailer
Algunas veces hemos necesitado que una aplicación nos mande un correo, ya sea porque hemos hecho un servidor y necesitamos que se nos notifique de algún evento con urgencia, o porque tenemos un programa ejecutándose un servidor (o supercomputador) en algún otro país realizando cómputos que puedan tardar horas o días y un simpático email diciendo “trabajo terminado” es una buena forma de saber que los datos procesados están listos. O porque tenemos un programita vigilando quién se sienta al pc, y en cuanto la webcam detecte movimiento se captura una foto y hace falta mandarla por correo.
Sea lo que sea, enviar un correo electrónico con .NET es una labor realmente sencilla. Simplemente hay que hacer una ventanita similar a la de la imagen que acompaña este artículo.
Y el código fuente que la alimenta es el siguiente:
using System;
using System.Windows.Forms;
using System.Net;
using System.Net.Mail;

namespace mailExample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //Evento para cuando pulsamos el botón "enviar"
        private void button1_Click(object sender, EventArgs e)
        {
            //La cadena "servidor" es el servidor de correo que enviará tu mensaje
            string servidor = "un.servidor.smtp.válido";
            // Crea el mensaje estableciendo quién lo manda y quién lo recibe
            MailMessage mensaje = new MailMessage(
               emisor.Text,
               receptor.Text,
               asunto.Text,
               mensaje.Text);

            //Envía el mensaje.
            SmtpClient cliente = new SmtpClient(servidor);
            //Añade credenciales si el servidor lo requiere.
            cliente.Credentials = CredentialCache.DefaultNetworkCredentials;
            cliente.Send(mensaje);
        }
    }
}

Cronometrar el tiempo con .NET (C#)

En el post anterior sobre paralelismo se ha hecho uso de una técnica muy sencilla (y eficaz) para medir tiempos de ejecución para la plataforma .NET,

Una utilidad es por ejemplo, controlar el tiempo que se tarda en finalizar una tarea para poder identificar (a mano) cuellos de botella, programar un cronómetro, etc.

//Guarda la hora justo antes del proceso a cronometrar
DateTime tiempo1 = DateTime.Now;

/*
 * ... Algun cómputo por aquí ...
 */

//Guarda la hora al finalizar
DateTime tiempo2 = DateTime.Now;

//Crea un "intervalo temporal"
TimeSpan total = new TimeSpan(tiempo2.Ticks - tiempo1.Ticks);

//Ya puedes mostrar en pantalla o guardar en una cadena
// (o lo que sea) el tiempo transcurrido (con total precisión)
System.Console.WriteLine(total.ToString());

Ejemplo con Parallel.FX

Parallel.FX es una librería (actualmente en Community Technology Preview, o sea, que ni siquiera es beta) diseñada para facilitar el aprovechamiento de los procesadores multicore-manycore a los programadores.

La programación paralela realmente supone un cambio en la forma de pensar de los programadores, especialmente si hay que gestionar los hilos manualmente, por eso esta librería intenta facilitar enormemente esa tarea.

Por ello, y en primer lugar, tenemos que instalarnos el .NET framework 3.5 (el último que hay actualmente), que trae por defecto la instalación de Visual Studio 2008 (Descarga disponible por ELMS, cortesía del servicio de informática) y a continuación, hay que instalar la librería Parallel.FX desde el centro de descargas de Microsoft. Está en inglés, pero eso no es una sorpresa (Parallel.FX ni siquiera es beta, recordáis?)

Para este ejemplo, vamos a necesitar únicamente una aplicación Windows, en la que vamos a utilizar tan sólo dos botones y un richTextBox. De manera opcional se puede añadir un ProgressBar cuyo estilo sea “marquee” para comprobar cuándo y cómo se queda congelada la aplicación al ejecutar los bucles de prueba.

parallel.example (Visual Studio, C#)

Una vez tenemos la ventana con los botones y el richtextbox hay que agregar una referencia a System.Threading en el proyecto. El motivo para esto es que deseamos utilizar la versión de System.Threading que nos proporciona  Parallel.FX en vez de utilizar la que trae .NET 3.5. Sabremos que utilizamos la versión correcta porque en las propiedades de la referencia aparece la siguiente descripción: Parallel Extensions to the .NET Framework.

Una de las herramientas más útiles proporcionadas por Parallel.FX es el bucle Parallel.For, cuya sintaxis se muestra en el código incluído al artículo.

Una vez hecho todo eso (Instalar .NET 3.5, Instalar Parallel.FX, Crear nuevo proyecto win32, Añadir los botones y el richtextbox a la ventana, Agregar referencia a System.Threading) tan sólo queda reemplazar el código fuente predeterminado de la ventana por el siguiente:

//Ejemplo que usa Parallel.FX
using System;
using System.Windows.Forms;
using System.Threading;
//Aplicación paralela Ejemplo
namespace Parallel.Example
{
  public partial class Form1 : Form
  {
  public Form1()
  {
  InitializeComponent();
  }
  //Bucle normal
  private void button1_Click(object sender, EventArgs e)
  {
  DateTime t1 = DateTime.Now;
  //Hacer 20 veces
  for (int i = 0; i < 20; i++)   {   //Dormir 100 milisegundos   Thread.Sleep(100);   }   DateTime t2 = DateTime.Now;   //Calcular tiempo transcurrido   TimeSpan t = new TimeSpan(t2.Ticks - t1.Ticks);   this.richTextBox1.Text = t.ToString();   }   //Bucle con Parallel.FX   private void button2_Click(object sender, EventArgs e)   {   DateTime t1 = DateTime.Now;   //Hacer 20 veces   System.Threading.Parallel.For(0, 20, delegate(int i)   {   //Dormir 100 milisegundos   Thread.Sleep(100);   });   DateTime t2 = DateTime.Now;   //Calcular tiempo transcurrido   TimeSpan t = new TimeSpan(t2.Ticks - t1.Ticks);   this.richTextBox1.Text = t.ToString();   }   } } [/sourcecode] Como anticipo, indico que el primer bucle (el no paralelo) tardará alrededor de dos segundos en finalizar, mientras el bucle que usa el Parallel.For tardará alrededor de 1 segundo en un procesador dual core (o medio segundo en un quad core). Como curiosidad, veis que Parallel.For es en realidad una función con tres parámetros: Inicio, Fin y Función_a_Ejecutar (El delegate).

Incrustación de aplicaciones con System.AppDomain

Con C#, y gracias a System.AppDomain extender la funcionalidad de una aplicación mediante plugins es un juego de niños. Una forma un tanto bruta de hacerlo, es considerar que los plugins son programas externos que ejecutan una serie de acciones necesarias y pueden devolver un valor (en forma de archivo en disco). Un ejemplo de este tipo de plugins lo tenemos en la implementación de los plugins para el programa de edición gráfica GIMP (Gnu Image Manipulation Program), el cual se vale de multitud de pequeños plugins en forma de programas ejecutables que se utilizan para aplicar filtros o efectos a una imagen.

En este caso, vamos a hacer un programa muy sencillo que funcione como un servidor de aplicaciones, de forma que dos o más aplicaciones se puedan lanzar simultáneamente en diferentes hilos, lo que permite aprovechar los procesadores multicore ejecutando cada aplicación en cores distintos.

Forma de uso del código: Se crean dos proyectos de consola, se copia el código fuente del servidor en uno, y el del programa ejemplo en otro. Una vez creados se generan los dos, y se copian a la carpeta raíz ( C:\ ), y se ejecuta el programa servidor. Éste incrustará dos copias del programa ejemplo, que imprime cierto número de veces su identificador de ejecución único, y se podrá observar cómo los resultados impresos por cada programa se van intercalando gracias al paralelismo de usar hilos.

Servidor (programa que incrusta otros programas en hilos):

using System;
using System.Threading;
//using System.Reflection;
namespace remoteInvoker
{
  class Program
  {
    static void Main(string[] args)
    {
      //Mostrar el AppDomain predefinido.
      string callingDomainName = Thread.GetDomain().FriendlyName;
      Console.WriteLine(”AppDomain Servidor: “+callingDomainName);
      //Invoca al creador de aplicaciones
      crearAplicacion(@”c:\appdomainExperiment.exe”);
      crearAplicacion(@”c:\appdomainExperiment.exe”);
      //Fin
      Console.WriteLine(”Server: exit”);
      Console.ReadKey(true);
    }

    /// Crea un hilo que ejecuta una aplicación
    private static void crearAplicacion(string aplicacion) {
      Aplicacion app = new Aplicacion(aplicacion);
    }
  }

  /// Incrusta un ensamblado en un hilo para ejecutarlo
  class Aplicacion {
    // Nombre (url) de la aplicación
    string appName;

    /// Constructor, crea un dominio predeterminado
    public Aplicacion(string aplicacion) {
      appName = aplicacion;
      Thread appThread = new Thread(new ThreadStart(doWork));
      appThread.Start();
    }

    /// Método de ejecución del hilo
    private void doWork(){
      //Crea un dominio de ejecución para este hilo
      AppDomain dominio = AppDomain.CreateDomain(”serverDomain”);
      //Ejecuta el ensamblado
      dominio.ExecuteAssembly(appName);
      //Descarga el Dominio
      AppDomain.Unload(dominio);
    }
  }
}

Programa de Ejemplo:

using System;
using System.Threading;
namespace appdomainExperiment
{
  class Program
  {
  static void Main()
  {
  System.Console.BackgroundColor = ConsoleColor.Blue;
  Console.WriteLine(”Hola Mundo! (Método Principal)”);

//Obtiene el identificador único de ensamblado en ejecución
  Guid k = System.Guid.NewGuid();
  for (int i = 0; i < 10; i++)   {   Console.WriteLine(k.ToString());   Thread.Sleep(10);   }   try   { //Escribe el nombre de dominio de la aplicación   Console.WriteLine(”AppDomain Cliente: ” +   System.AppDomain.CurrentDomain.DomainManager.EntryAssembly.FullName);   }   catch   {   Console.WriteLine(”AppDomain Cliente: Aplicación independiente”);   }   System.Console.BackgroundColor = ConsoleColor.Black;   }   } } [/sourcecode]

Cómo mueren las empresas de software?

Orson Scott Card lo dejó bien claro con un relato corto: Las empresas mueren cuando se intenta forzar a los trabajadores (léase programadores) a ir en traje acorbatado y a perder su individualidad.

Texto completo en

http://www.zoion.com/~erlkonig/writings/programmer-beekeeping.html

(Tal vez lo traduzca algún día…)