Y cuando afirmo eso, no lo hago en un sentido peyorativo, sino que de una buena manera. S? que somos varios los que aprendimos C# probablemente con la versi?n 1.0 o la 1.1 del Framework .NET y nos hemos quedado con las caracter?sticas de esas versiones, sin investigar las cosas nuevas que trae C# 2.0. Y deber?amos ponernos al dia ya que pronto llegar? C# 3.0 con a?n m?s cambios y m?s adelante Cω.

Lo m?s probable es que la mayor?a sepamos lo que son los tan publicitados Generics, algo que nos contaron que era incre?ble, para luego conocerlo y descubrir que? en verdad era incre?ble. Tambi?n probablemente hayamos al menos visto los Partial Types, algo que los WinForms usan a menudo: ubicando el c?digo de definici?n del Form en un archivo y el c?digo del programador en otro, pero reconociendo siempre a ambos archivos como definiciones complementarias de la misma clase. Sin embargo esos fueron probablemente los ?nicos grandes cambios que supimos que ven?an con la ?ltima versi?n de este lenguaje que tanto ha dado que hablar y que cada d?a m?s son los programadores que se suman a sus filas.

Muchos lo critican, es verdad, de la misma manera como lo han hecho con Java y como lo hicieron antes con C++. Pero cuando escucho a estos cr?ticos me vienen a la mente las palabras del maestro Bjarne Stroustrup (padre de C++): ?Hay dos tipos de lenguajes de programaci?n: aquellos que todo el mundo critica y aquellos que nadie los usa.?

Enfim, no quiero salirme del punto principal: las cosas nuevas de la versi?n 2.0 de C# que a?n no nos hemos familiarizado lo suficiente adem?s de Generics y Partial Types.

yield return

Para empezar, tomemos el caso de la nueva expresi?n yield return. Esta expresi?n, pese a lo peque?a y extra?a que pueda parecer, nos ahorrar? bastante trabajo cuando tengamos que desarrollar nuestras propias colecciones de objetos y har? que nuestro c?digo se vea mucho m?s elegante. Me explicar?.

En muchas ocasiones hemos querido y necesitado poder iterar sobre una clase personal de la siguiente manera:

MiColeccion miColeccion = new MiColeccion();
foreach (object obj in miColeccion)
{
????? System.Console.Out.WriteLine(obj.ToString());
}

Sin embargo, un c?digo elegante como ?ste ten?a su precio: nuestra clase a ser iterada, en este caso MiColeccion, deb?a implementar la interfaz IEnumerable con su m?todo GetEnumerator. Por lo tanto, la definici?n de nuestra clase MiColeccion deb?a ser semejante a lo siguiente:

using System;
using System.Collections;
namespace CSharp
{
????? public class MiColeccion : IEnumerable
????? {
??????????? public IEnumerator GetEnumerator()
??????????? {
????????????????? return null;
??????????? }
????? }
}

Con una clase como esta nuestro c?digo compilar?a pero no ser?a ?til, pues GetEnumerator devuelve nulo. En realidad la idea era devolver nuestra propia implementaci?n de un Enumerator. De modo que ten?amos que devolver una clase que implementara la interfaz IEnumerator, con sus m?todos Reset, Current y MoveNext. Nuestro c?digo quedaba algo as? como esto:

using System;
using System.Collections;
namespace CSharp
{
????? public class MiColeccion : IEnumerable
????? {
??????????? MiEnumerador miEnumerador = new MiEnumerador();
??????????? public IEnumerator GetEnumerator()
??????????? {
????????????????? return miEnumerador;
??????????? }
????? }
????? public class MiEnumerador : IEnumerator
????? {
??????????? private string[] _paises = {“Argentina”, “Bolivia”, “Brasil”, “Chile”, “Per?”};
??????????? private int _contador = -1;
??????????? public void Reset()
??????????? {
????????????????? _contador = -1;
??????????? }
??????????? public object Current
??????????? {
????????????????? get
????????????????? {
??????????????????????? if (_contador < 5)
????????????????? ????? {
??????????????????????? ????? return _paises[_contador];
??????????????????????? }
??????????????????????? else
??????????????????????? {
???????????????????????????? return null;
??????????????????????? }
????????????????? }
??????????? }
??????????? public bool MoveNext()
??????????? {
????????????????? if (_contador < 5)
????????????????? {
??????????????????????? _contador++;
??????????????????????? return true;
????????????????? }
????????????????? else
????????????????? {
??????????????????????? return false;
????????????????? }
??????????? }
????? }
}

Ahora s? estar?amos devolviendo correctamente una instancia de MiEnumerador, una clase personal que implementa la interfaz IEnumerator. Como se puede notar, eran los m?todos Reset, Current y MoveNext los que en verdad permit?an la iteraci?n dentro de nuestra colecci?n personal de objetos.

Todo este trabajo para definir una clase que implementara la interfaz IEnumerator como es el caso de MiEnumerador se termina con C# 2.0 y la nueva expresi?n yield return.

As? como dicen que una imagen dice m?s que mil palabras, yo digo que un ejemplo de c?digo hace lo mismo:

using System;
using System.Collections;
using System.Collections.Generic;
namespace CSharp
{
??? public class MiColeccion : IEnumerable
??? {
??????? public IEnumerator GetEnumerator()
??????? {
???????? ???yield return “Argentina”;
??????????? yield return “Bolivia”;
??????????? yield return “Brasil”;
??????????? yield return “Chile”;
??????????? yield return “Per?”;
??????? }
??????? IEnumerator IEnumerable.GetEnumerator()
??????? {
??????????? return null;
??????? }
??? }
}

?Qu? te parece? Acabo de reescribir el c?digo de la clase MiColeccion, funcionando de la misma manera, pero sin tener que crear una clase MiEnumerador con todos los m?todos que ya vimos.

Para ello us? dentro del m?todo GetEnumerator de MiColeccion un yield return por cada item que yo quer?a iterar. A pesar de incluir la palabra clave return, yield return no se sale del m?todo en el momento que es invocado. M?s bien le retorna al Enumerator que encubre el m?todo GetEnumerator cada uno de los items de la colecci?n. Y adem?s usa Generics para informar el tipo de los items que ser?n devueltos.

Bastante elegante, ?no lo crees as?? Obviamente que no es necesario escribir un yield return por cada item. Uno podr?a escribir el yield return una ?nica vez dentro de alg?n tipo de loop, como por ejemplo:

using System;
using System.Collections;
using System.Collections.Generic;
namespace CSharp
{
??? public class MiColeccion : IEnumerable
??? {
??????? private string[] _paises = { “Argentina”, “Bolivia”, “Brasil”, “Chile”, “Per?” };
??????? public IEnumerator GetEnumerator()
??????? {
??????????? for (int i = 0; i < _paises.Length; i++)
??????????? {
??????????????? yield return _paises[i];
??????????? }
??????? }
??????? IEnumerator IEnumerable.GetEnumerator()
??????? {
??????????? return null;
??????? }
??? }
}

El IEnumerable.GetEnumerator() que retorna un null en el c?digo anterior es necesario ?nicamente para la compilaci?n pues mantiene la compatibilidad con programas escritos con versiones anteriores de C#.

El c?digo que iterar?a sobre la clase anteriora ser?a muy semejante al c?digo del principio solo que ahora esperando recibir una colecci?n de strings. Esto ?ltimo adem?s asegura que este c?digo se ejecutar? m?s r?pido que el primero debido a que ya no es necesario el boxing y unboxing de un tipo object al tipo que nosotros necesitamos, en este caso string, para los items de la colecci?n.

MiColeccion miColeccion = new MiColeccion();
foreach (string str in miColeccion)
{
??? System.Console.Out.WriteLine(str);
}

?

?Has visto en alg?n c?digo de ejemplo en Internet algo como esto?:

int? i = algunObjeto.Value;

?Qu? diablos hace ese signo de interrogaci?n all?? Por extra?o que te pueda parecer, ese signo te ahorrar? mucho c?digo tedioso y repetitivo.

Un problema com?n para los desarrolladores de C# (y tambi?n de Java) sucede cuando queremos asignar el valor de alg?n objeto a un ?tipo primitivo? (int, long, double, bool, etc.) o a un objeto que ?representa? a un tipo primitivo (como Int32, Int64, DateTime, Double, Boolean, etc.) y ese valor en alg?n momento en tiempo de ejecuci?n es un null. Si no realizamos ninguna validaci?n previa y simplemente asignamos el valor null a nuestra variable de tipo primitivo, la aplicaci?n se cae. Esto es muy com?n que suceda especialmente cuando estamos asignando valores desde una base de datos ya sea mediante un DataSet o un DataReader hacia variables propias.

En el pasado hemos podido solucionarlo de varias formas pero todas ellas implicaban escribir c?digo repetitivo y tedioso.

Con C# 2.0 surge la soluci?n propia del lenguaje con la llegada de los ?Nullable Types?. El siguiente c?digo tanto es aceptado en tiempo de compilaci?n como es aceptable en tiempo de ejecuci?n:

Nullable var = new Nullable();
var = null;

Eso es mucho mejor que lo que hemos tenido que hacer en el pasado. Pero a?n mejor noticia es saber que ese mismo c?digo lo podemos escribir de la siguiente forma:

bool? var;
var = null;

M?s elegante, ?cierto? Ese signo de interrogaci?n que parec?a tan raro ahora ya deja de serlo. Es m?s, en la medida que lo vayas usando en tu c?digo ver?s como r?pidamente lo estar?s usando en todas partes.

Ah, otra cosa. Si despu?s necesitas averiguar si tu variable Nullable tiene o no un valor nulo, en lugar de hacer la t?pica pregunta ?if(var != null)? ahora puedes escribir m?s elegantemente ?if(var.HasValue)?. ?Qu? te parece?

Sin embargo, no debo dejar de mencionar el hecho de que ese signo de interrogaci?n sigue siendo criticado por muchos como poco natural y poco intuitivo. A muchos les hubiera gustado algo m?s del tipo:

nullable bool var = null;

Lo cual es bastante m?s intuitivo. No obstante s? agregar?a otra palabra clave m?s al lenguaje, cosa que a muchos les disgustar?a. Por lo tanto es un asunto de purismo y de puristas. Lo importante desde mi punto de vista es que exista la opci?n de escribir menos c?digo tedioso, cosa que el ? definitivamente lo logra. La gente de Microsoft ver? a futuro si hace falta o no modificar la notaci?n.

Clases Est?ticas

En muchas ocasiones hemos tenido que crear clases con solamente m?todos est?ticos. Para que la clase no pudiese ser instanciada lo que hac?amos era definir un constructor privado.

Ahora con C# 2.0 podemos definir clases est?ticas, las cuales demandan que todos sus miembros sean igualmente est?ticos. Al hacerlo no necesitamos definir ning?n constructor para la clase en cuesti?n.

public static class MiClaseEstatica
{
???static public T MetodoEstatico ()
?? {…}

}

M?todos An?nimos

Lambda Calculus (http://en.wikipedia.org/wiki/Lambda_calculus), o la posibilidad de un lenguaje de permitir tratar a funciones como si fueran objetos de primera clase, es una caracter?stica por mucho tiempo soportada por lenguajes como Pascal, Lisp, Smalltalk, Eiffel o Python. En dichos lenguajes es posible, por ejemplo, pasar un m?todo como par?metro.

En C# esto se lograba gracias al uso de delegates. Un delegate es un objeto que referencia a un m?todo. Siempre que el delegate es invocado, el m?todo referenciado por ?ste es tambi?n llamado.

Uno de los principales usos que reciben los delegates son para el manejo de eventos de controles gr?ficos de WinForms. Por ejemplo, en la porci?n de c?digo donde se inicializan las propiedades de los controles de un WinForm, es com?n ver un c?digo como el siguiente:

button1.Click += new EventHandler(ManejaClick);

Luego en alguna parte de la misma clase encontramos la definici?n de ManejaClick:

void ManejaClick(object sender, EventArgs e)
{
????? MessageBox.Show(?Se hizo click en button1.?);
}

No obstante, muchas veces parec?a incoveniente tener que crear un m?todo exclusivamente para ser luego invocado por un delegate, sobretodo cuando ?ste solo deb?a ser referenciado una vez.

Con m?todos an?nimos, el mismo c?digo anterior quedar?a de la siguiente manera:

button1.Click += new EventHandler(sender, e)
{
????? MessageBox.Show(?Se hizo click en button1.?);
}

Lo anterior significa que ahora podremos escribir un c?digo semejante al siguiente cuando deseemos ejecutar una porci?n de c?digo en un hilo distinto, sin tener que escribir necesariamente un m?todo a parte para esa finalidad:

public class MiClase
{
?? public void LanzarHilo()
?? {
????? Thread nuevoHilo = new Thread(delegate()
?????????????????????? ?????{
??????????????????????????????? MessageBox.Show(“Hola”);
??????????????????????????? });
????? nuevoHilo.Start();
?? }
}

pragma

Con C# 1.1 era posible deshabilitar ciertas advertencias del compilador ya sea mediante las propiedades del proyecto o mediante argumentos de l?nea de comando al invocar el compilador.

El problema era que la habilitaci?n / deshabilitaci?n ocurr?a sobre todo el proyecto. Ahora con C# 2.0 es posible habilitar / deshabilitar estas advertencias del compilador solo d?nde y cu?ndo lo deseamos mediante una directiva en el c?digo de nuestra aplicaci?n. Como siempre digo, un ejemplo de c?digo vale m?s que 1.000 palabras:

#pragma warning disable 169
public class MiClase
{
?? int m_Numero;
}
#pragma warning restore 169

::

Este signo te permitir? invocar a clases las que probablemente te causar?an prolemas en versiones anteriores de C#. Me refiero a clases cuyos nombres se pudiesen confundir con otras del mismo nombre que, aunque en distintos namespaces, seg?n nuestra ubicaci?n relativa en la estructura de namespaces al momento de invocar dicha clase, podr?amos confundir al compilador.

Para hacer claro cu?l es la clase que deseamos invocar, ahora tendremos la opci?n de obligar al compilador a partir su b?squeda de la clase en cuesti?n desde el nivel global, como en el siguiente c?digo:

namespace MiApp
{
?? class MiClase
?? {
????? public void MiMetodo()
????? {
???????? ::MiClase obj = new ::MiClase();
???????? obj.MiMetodo();?????

?????? }
?? }
}
public class MiClase
{
?? public void MiMetodo()
?? {
????? Trace.WriteLine(“Hola”);
?? }
}
?