|
Novedades en C# 2005 |
|
|
Autor: Unai Zorrilla Actualizado: 05/Jul/2004 |
Introducción
¿Que trae c# 2005 como novedades? Bueno esta pregunta seguro que se la está haciendo mucha gente, a través de una serie de artículos iremos viendo los cambios y novedades que llegan con c# 2.0 o ( c## como dicen algunos ). Lo más destacable en esta nueva versión del lenguaje es la inclusión de Generics ( para los conozcan c++ ( templates ) y para los de Lisp ( lambda ) ), Iteradores, métodos anónimos y algunas cosillas más que iremos viendo.
¿Que son los Generics?
Los Generics son clases, estructuras, delegados interfaces y métodos que permiten parametrizarse por el tipo de datos con el fin de guardar y manipular estos. Lo mejor para tratar de entender esto es ver algunos ejemplos sobre como trabajábamos antes y como 'debemos' trabajar con c# 2005.
En el siguiente código veremos un ejemplo de como manejábamos la clase Stack hasta ahora para guardar por ejemplo trabajos ( Job ) en un programa cualquiera:
using System; using System.Collections; namespace Ejemplo1 { /// <summary> /// Ejemplo, uso sin generics /// </summary> class MainClass { private Stack pila; public MainClass() { pila = new Stack(); } /// <summary> /// Punto de entrada principal de la aplicación. /// </summary> public void AddJob() { Job trabajo = new Job(); pila.Push((object)trabajo); trabajo = (Job)pila.Pop(); } [STAThread] static void Main(string[] args) { MainClass c = new MainClass(); c.AddJob(); } } public class Job { private string _persona; private DateTime _fecha; public string Persona { get { return this._persona; } set { this._persona = value; } } public DateTime Fecha { get { return this._fecha; } set { this._fecha = value; } } public Job() { this._persona = "empty"; this._fecha = System.DateTime.Now; } } }Es fácil ver que tanto al añadir como al quitar elementos de la pila es necesario un boxin (unboxing) de los datos, en este proceso, además en tiempo de ejecución es necesario un chequeo de tipos lo que resta ' performance ' a nuestras aplicaciones. Con la llegada de Generics podremos agilizar este proceso de una manera sencilla y rápida. Este mismo código con Generics se podría implementar de la siguiente forma:
#region Using directives using System; using System.Collections.Generic; using System.Text; #endregion namespace Ejemlo1 { class MainClass { private Stack<Job> pila; public MainClass() { this.pila = new Stack <Job>(); Job trabajo = newJob(); pila.Push(trabajo); trabajo = pila.Pop(); } public void AddJob() { Job trabajo = new Job(); } [STAThread] static void Main(string[] args) { MainClass c = new MainClass(); c.AddJob(); } } public class Job { private>font color = #0000FF>string _persona; public/**/ string Persona { get { return _persona; } set { _persona = value; } } private DateTime _fecha; public/**/ DateTime Fecha { get { return _fecha; } set { _fecha = value; } } public Job() { this._persona = "empty"; this._fecha = System.DateTime.Now; } } }Vemos como ahora la clase Stack se define Stack<Job> pila = new Stack<Job>(); lo que nos ahora los cast y facilita el proceso de trabajar directamente con el tipo de datos Job.
Los Generics además poseen un fuerza mayor ya que permiten la restricción de tipos de datos, algo necesario que veremos a continuación.
Restricciones 'Constraint' para los Generics
Supongamos para el Add de Dictionary necesitamos compara las claves usando CompareTo, con generics tendríamos
public class Dictionary<K,V> { public void Add(K key,V value) { ... if(key.CompareTo(x)<0) { ... } } }Esto provocaría un error si K no implementara IComparable, incluso haciendo un cast a IComparable podría lanzarse InvalidCastException si esta interface no fuera implementa por K, por suerte c# 2005 facilita la restricciones en la instanciación de Generics por medio del constraint where, para el caso anterior podríamos habilitar la restricción de la siguiente forma
public class Dictionary<K,V> where K : IComparable { public void Add(K key,V value) { ... if(key.CompareTo(x)<0) { ... } } }Mediante la cláusula where K: ICompable habilitamos la restricción sobre la implementación de Dictionary a clases que implementen la interface IComparable.
Dentro de las restricciones me gustaría destacar lo siguiente, supongamos que se implementa una clase genérica con la cláusula where de la siguiente forma:
where T : new()
Esta restricción permite tipos como parámetro de E ha aquellos con un constructor público y que las instancias de este genérico se creen con new T()
Métodos Genéricos
Imaginaos que deseamos implementar un metod de Push Multiple de trabajos el pila que vimos anteriormente, un primera implementación seria
void PushMultiple(Stack<Job> pila,params Job[] Trabajos) { foreach(Job trabajo en Trabajos) { pila.Push(trabajo);} }Esto funcionaría pero tenemos una restricción a construcciones con Stack<Job> , en c# 2005 podemos implementar métodos genéricos y para trabajar con distintos datos. La implementación del método genérico sería la siguiente:
void PushMultiple<T>(Stack<T> pila,params T[] Valores) { foreach(T valor in Valores) { pila.Push(valor);} }Con lo que ahora podríamos realizar cualquiera de las siguientes instancias:
Stach<int> pila = new Stack<int>(); pila.PushMultiple(pila,1,2,3,4); Stach<Job> pila = new Stack<Job>(); pila.PushMultiple(pila,trabajo1,trabajo2,trabajo3,trabajo4);