lunes, 24 de mayo de 2010

C# 3.0 y los métodos de extension

Si estas incursionando en el uso de linq a estas alturas y no has seguido de cerca las modificaciones que se le han hecho a c# a partir de su version 3.0 (me consta que ha llovido bastante, pero nunca es tarde para meditar sobre cosas del pasado), este articulo puede resultarle util.


Seguramente has presionado Ctrl + Spacio, seguido de una instancia de un tipo de datos que me represente una coleccion, pudiesemos escoger cualquiera de los siguiente namespace:

System.Collections,
System.Colleciotns.Generic,
System.Linq


asi que la siguiente imagen te puede resultar familiar

Fig con metodos de extension para mostrar el icono distintivo de estos metodos


Pues la flechita azul, indica que se trata de un metodo de extension. ahora bien empecemos por dar una definicion.

Metodo de extension: es un metodo estatico de una clase estatica, que usted puede llamar como si fuese un metodo de instancia de una clase diferente a donde se definio.

interesante no!!!!


SITUACION PROBLEMICA

Para entender bien esto, creo que lo mejor es a partir de un problema concreto, tratar de resolverlo con lo que existia antes y luego ver como los metodos de extension permiten resolverlo.


Supongamos que queremos incorporle a los datos de tipo String, la funcionalidad de saber si la cadena tiene espacio en blancos.


lo primero que nos viene a la mente es un metodo estatico, que reciba como parametros un string devolveria true/false.


namespace string_utiles
{
public class Utils
{
public static bool tiene_espacios(string input_str)
{
return input_str.Contains(" ");
}
}
}



de manera que un ejemplo de su uso seria:


using string_utiles;
...
...

String s = "cadena con espacios en blanco";
bool tiene = Utils.tiene_espacios(s);


perooooo....
no seria mas elegante que este metodo se pudiese invocar como un metodo de la propia instancia, veamos


String s = "cadena con espacios en blanco";
bool tiene = s.tiene_espacios();


porque al final de cuentas, es responsailidad de la cadena, saber si tiene o no, espacios en blanco


desafortunadamente String, es un clase sealed (sellada), lo que en español quiere decir que no se puede heredar de ella, o que en ella murio el cuento ;)....

porque si no fuese asi, podriamos hacer algo como esto,


class CustomString : String
{
public bool tiene_espacios()
{
return this.Contains(" ");
}
}


pero entonces tendriamos un problema, que nuestros tipos de datos string, tendrian que pasar a ser de tipo CustomString, y esto implica mucho cambio de codigo... ufff... esto no tiene nada de buenas practicas eh....


pero bueno, la solucion ideal esta por ahi, incluirle un metodo a los tipos de datos string, de manera que no haya que heredar de la clase String, pero se invoque como si fuese un metodo de instancia... mmmmm ... esto me recuerda al principio de la programacion orientada a objetos, "abierto a la extension y cerrado a la modificacion".

y esto es posible gracias a los metodos de extension.

como quedaria...



namespace string_utiles
{
public static class Utils
{
public static bool tiene_espacios(this string s)
{
return s.Contains(" ");
}
}
}


using string_utiles;

String s = "cadena con espacios en blanco";
bool tiene = s.tiene_espacios();



DEFINIENDO E INVOCANDO LOS METODOS DE EXTENSION

definiendo.....


namespace [nombre_namespace]{
public class static [nombre_clase]
{
public static [return type] [nombre_metodo] (this [tipo instancia] nombre_instancia ,param1, param2, ..., param n)
{
//statement.....
}
}

}



reglas para la definicion:
-los metodos deben definirse dentro de una clase estatica
-los metodos deben ser estaticos
-el primer parametro del metodo, debe estar precedido con la palabra clave this, y debe ser del tipo al que le queremos incluir este metodo de extension.


invocando....


using [nombre_namespace];
...

[tipo instancia] instancia = [valor];

instancia.[nombre_metodo](param1, param2,..., param n);
...


-basta con incluir el namespace, donde se encuentre la clase estatica, que contenga los metodos de extension, automaticamente, seran reconocidos.
-los metodos de instancia tiene tienen precedencia sobre los metodos de extension, en caso de que coincida en ombre y parametros.



Espero ahora ya sepas cuando estas usando un metodo de extension que hay detras de ello, y ademas puedas encontrarle alguna utilidad en tus desarrollos y te atrevas a definir los tuyos propios, como comente anteriormente, son un elemento que favorece el principio de abierto a la extension, cerrado a la modificacion.