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);
        }
    }
}

LINQ hecho fácil

Acabo de encontrar una especie de notepad para escribir consultas LINQ. Se llama LINQpad y es una pequeña aplicación (2 megas) muy útil para empezar a crear consultas con esta herramienta de consulta tan potente.

Además viene cargada con un buen montón de ejemplos y minitutoriales, así como un asistente de conexión rápida a bases de datos SQL-Server (Como el incluído en Visual Studio, o en las versiones express) para poder hacer consultas sobre la Base de Datos casi sin pensar. También se incluyen ejemplos para hacer consultas sobre arrays de datos y demás.

Hale, a disfrutar el Linqpad!

Publicado en C#, Computacion. Etiquetas: , , . Leave a Comment »

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]

External Storage Unit detection with C# in .NET (USB, Card Readers, etc)

It seems that the spanish written post for unit detection is pretty popular between my readers (and particularly Google), so I thought that time had come to upgrade it for a more international language.

This piece of code basically consists in a couple of methods that can enable any application to detect whenever a new storage device has been inserted into the computer, whether it is a CD/DVD, an USB key, a SD/MMC memory card, a external HDD… and to identify the newly inserted device unit’s name. This methods can be modified to fit the requirements of an existent application, or to build a new one that can use this functionality en new and creative ways (such as automated backups of the data on our USB Keys when inserting them and viceversa).

//It IS mandatory to include this reference
using System.Runtime.InteropServices;

//
//   You can add any code you want…
//   HERE …..
//

//Data structure that stores the connection management
[StructLayout(LayoutKind.Sequential)]
public struct DEV_BROADCAST_VOLUME
{
  public int dbcv_size;
  public int dbcv_devicetype;
  public int dbcv_reserved;
  public int dbcv_unitmask;
}

//Method to overwrite that manages the arrival of new storage units
protected override void WndProc(ref Message m)
{
  //This definitions are stored in “dbt.h” and “winuser.h”
  // There has been a change in the devices
  const int WM_DEVICECHANGE = 0×0219;
  // System detects a new device
  const int DBT_DEVICEARRIVAL = 0×8000;
  // Device removal request
  const int DBT_DEVICEQUERYREMOVE = 0×8001;
  // Device removal failed
  const int DBT_DEVICEQUERYREMOVEFAILED = 0×8002;
  // Device removal is pending
  const int DBT_DEVICEREMOVEPENDING = 0×8003;
  // The device has been succesfully removed from the system
  const int DBT_DEVICEREMOVECOMPLETE = 0×8004;
  // Logical Volume (A disk has been inserted, such a usb key or external HDD)
  const int DBT_DEVTYP_VOLUME = 0×00000002;
  switch (m.Msg)
  {
   //If system devices change…
   case WM_DEVICECHANGE:
    switch (m.WParam.ToInt32())
    {
     //If there is a new device…
     case DBT_DEVICEARRIVAL:
     {
      int devType = Marshal.ReadInt32(m.LParam, 4);
      //…and is a Logical Volume (A storage device)
      if (devType == DBT_DEVTYP_VOLUME)
      {
       DEV_BROADCAST_VOLUME vol;
       vol = (DEV_BROADCAST_VOLUME)Marshal.PtrToStructure(
m.LParam, typeof(DEV_BROADCAST_VOLUME));
      MessageBox.Show(
        ”A storage device has been inserted, unit: ” +
        UnitName(vol.dbcv_unitmask));
      }
     }
    break;
    case DBT_DEVICEREMOVECOMPLETE:
     MessageBox.Show(”Device removed from system.”);
    break;
   }
   break;
  }
  //After the custom manager, we want to use the default system’s manager
  base.WndProc(ref m);
}

//Method to detect the unit name (”D:”, “F:”, etc)
char UnitName(int unitmask)
{
  char[] units ={ ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’,
    ’H’, ‘I’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘O’, ‘P’,
    ’Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’, ‘Y’, ‘Z’ };
  int i = 0;
  //Convert the mask in an array, and search
  //the index for the first occurrenc (the unit’s name)
  System.Collections.BitArray ba = new
    System.Collections.BitArray(System.BitConverter.GetBytes(unitmask));
  foreach (bool var in ba)
  {
   if (var == true)
   break;
  i++;
  }
return units[i];
}

I’d be really pleased to know if this was useful 🙂

Publicado en C#. Etiquetas: , , , . 4 Comments »